mithran.yaml reference¶
mithran.yaml lives at your repo root and describes the app Forge builds and
serves. map onboard scaffolds a starter when run with
--repo-dir <checkout> and no mithran.yaml exists. That starter is a basic
HTTP MithranApp skeleton; review its app ID, project/app ref, runtime, startup
command, exposure, and app-environment policy before the first deploy.
The manifest is reviewed before the image is built. A review block means Forge could read the file and found a contract or policy problem; it does not mean your Dockerfile or app process has run yet.
See Account context and app environments for setup context and app-environment naming. See the Glossary for tenant, account, project, app, deploy, publish, public, protected, and MAP naming terms.
apiVersion: map.mithran/v1
kind: MithranApp
metadata:
app_id: my-app
name: My App
identity:
project_ref: app:my-app
capabilities:
- kind: http
route: /
runtime: nodejs22
startup:
command: npm start
resources:
requests:
cpu: 250m
non_secret_env:
- { name: NODE_ENV, value: production }
public_edge:
type: platform
exposure: protected
app_env:
preview:
branch_pattern: "^refs/heads/main$"
image_tag: preview
production:
branch_pattern: "^refs/(heads/release/.*|tags/release/.*)$"
image_tag: prod
Required shape¶
A deployable self-service HTTP app manifest needs four groups:
| Group | Purpose |
|---|---|
| API identity | apiVersion and kind tell Forge which manifest schema to parse. |
| App identity | metadata names the app. In the self-service path, use the same label in the served app ref, such as app:my-app, so route and publish commands address the expected hostname. |
| Project identity | identity.project_ref records the project/app ref agreed during onboarding. |
| Capabilities | capabilities describes the HTTP service Forge starts and routes. |
Everything else controls resources, environment variables, edge exposure, or environment mapping.
Read the reference by ownership:
| Field group | Use |
|---|---|
| Required app contract | apiVersion, kind, metadata.app_id, metadata.name, identity.project_ref, and capabilities[]. A self-service HTTP app needs these before Forge can build and route it. |
| Runtime configuration | resources, non_secret_env, and app_env values. These describe build/runtime shape and app-environment metadata. |
| Route exposure | public_edge.type and public_edge.exposure. These set the reviewed app-route exposure value. public serves anonymously; all other values keep Forge auth required. |
| Account-reviewed policy metadata | secret_bindings, oauth_api, public_edge.tier, public_edge.allow, and public_edge.review_exceptions. Use these only when the account has approved the corresponding policy. |
| Descriptive metadata | metadata.description, metadata.tags, metadata.domain, metadata.labels, and identity.environment. These are accepted manifest metadata; they do not select app environments or account context. |
Minimal deployable shape:
apiVersion: map.mithran/v1
kind: MithranApp
metadata:
app_id: my-app
name: My App
identity:
project_ref: app:my-app
capabilities:
- kind: http
route: /
runtime: nodejs22
startup:
command: npm start
This is the smallest useful shape for review. The app still needs a repo-root
Dockerfile and a process that follows the HTTP app contract
before runtime can become ready.
Field reference¶
| Field | Required | Notes |
|---|---|---|
apiVersion |
yes | map.mithran/v1. MAP is the manifest API namespace; keep this value as shown. |
kind |
yes | MithranApp. |
metadata.app_id |
yes | App ID used in manifest review and evidence. For self-service apps, choose a DNS-friendly value and keep it aligned with the app ref label, usually app:<metadata.app_id>, so the published clean public URL uses the expected hostname. |
metadata.name |
yes | Human-readable name. |
metadata.description |
no | Optional human-readable description. |
metadata.tags[] |
no | Optional tags. Forge normalizes tags in sorted order. |
metadata.domain |
no | Optional key/value metadata. This does not configure DNS or route ownership. |
metadata.labels |
no | Optional key/value metadata. |
identity.project_ref |
yes | Project/app ref agreed during onboarding. In the self-service path this is the served app ref, commonly app:<metadata.app_id>. |
identity.environment |
no | Optional identity metadata. It does not select account context or the app environment. |
capabilities[] |
yes | One or more app capabilities. Accepted kind values are http, worker, and scheduler. The self-service docs cover HTTP apps. See Capability support. |
resources.requests.* |
no | Resource request values, such as cpu: 250m or memory: 512Mi. |
resources.limits.* |
no | Resource limit values, such as cpu: "2" or memory: 2Gi. |
resources.concurrency.max_in_flight |
no | Maximum in-flight work for the app process. |
resources.replicas.min / max |
no | Requested replica bounds. |
non_secret_env[] |
no | Plain config as { name, value }. Committed to the repo, so never secrets. |
secret_bindings[] |
no | Account-reviewed secret binding metadata only. Each entry needs name, mount.kind, mount.target, purpose, required, and rotation.required. Do not include secret values or raw provider refs. |
oauth_api.* |
no | Account-reviewed OAuth API policy metadata. When the block is present, include enabled, path, and scope.default. When enabled: true, audience and allowed_methods must also be non-empty. |
public_edge.type |
no | Required when public_edge is present. Must be platform. |
public_edge.exposure |
no | Required when public_edge is present. Supported values are protected, none, public-redirect, and public. public-redirect is a manifest exposure value, not an access-policy value. See App access and sharing. |
public_edge.tier |
no | Account-reviewed placement metadata. reserved selects reserved placement. Omit it, or use free, for the default free-app placement. Unrecognized values are normalized to free. |
public_edge.allow[] |
no | Account-reviewed typed public-edge allow entries. Supported type values are oauth_api and admin_redirect; unknown fields are rejected. |
public_edge.review_exceptions[] |
no | Account-reviewed review exception metadata. Each entry requires policy_ref and reason; scope is optional. |
app_env.<env>.branch_pattern |
yes, when the app environment exists | Regex metadata for the refs associated with that app environment. |
app_env.<env>.auto_deploy_refs[] |
no | Git ref patterns for app-env resolution on webhook auto-deploy candidates. Entries must start with refs/; exact refs and a single trailing * prefix glob are supported. |
app_env.<env>.image_tag |
yes, when the app environment exists | Image tag for that environment. |
app_env.<env>.env_overrides[] |
no | Non-secret environment overrides for that app environment. Same secret checks as non_secret_env. |
app_env.<env>.replicas.min / max |
no | Replica bounds for that app environment. |
app_env.<env>.policy.* |
no | Review policy switches: protect_in_review, require_map_review, and allow_traffic_without_review. Unknown policy fields are rejected. |
App ID and App Ref¶
metadata.app_id identifies the app in manifest review and evidence:
metadata:
app_id: inventory-portal
name: Inventory Portal
identity:
project_ref: app:inventory-portal
For self-service apps, use the same label in the served app ref you pass as
map onboard --app-ref, map versions, and map publish. With
app:inventory-portal, the
production clean public URL is:
Choose an app_id that is:
- stable across releases;
- short enough to type and recognize in logs;
- lowercase and DNS-friendly;
- specific enough that operators can identify the app without opening the repo.
If an operator gives you an app ref that does not match metadata.app_id, use
the operator-provided app ref for onboarding, route, version, and publish
commands. The hostname follows the served app ref; keep the manifest,
onboarding record, and release evidence aligned before publishing.
HTTP capability¶
The common app shape is one HTTP service:
The startup command must start a process that listens on the port in $PORT.
Forge waits for runtime readiness after the artifact starts.
If the container starts but the app never becomes ready, check the startup
command, port binding, Dockerfile, deploy status, deploy evidence when
available, and serving probe behavior together.
For framework examples and local Docker checks, see HTTP app contract.
Capability support¶
Manifest review validates capability shape before build. It does not prove the runtime process starts or that the route is ready.
| Capability kind | Route required by manifest review | Runtime required | Startup command required | Covered by the self-service app docs |
|---|---|---|---|---|
http |
yes | yes | yes | yes |
worker |
no | yes | yes | no |
scheduler |
yes | yes | yes | no |
Use kind: http for the customer self-service path documented here. The
worker and scheduler manifest kinds are accepted by manifest review, but
these docs do not define their customer runtime contract, deploy evidence, or
operator runbook. Do not use them as substitutes for a documented HTTP app.
runtime is manifest metadata for the app capability. Forge still builds from
the repo-root Dockerfile, records the first capability runtime in deploy
evidence, and starts the declared startup.command.
Environment variables¶
Use non_secret_env only for configuration that is safe to commit:
Do not put API keys, tokens, private keys, passwords, customer credentials, or secrets in this file. The manifest is source-controlled and visible to anyone with repo read access.
Forge rejects obvious secret-looking names and values in non_secret_env, such
as names containing secret, token, password, or private_key, the name
api_key, values starting with sk_live_, ghp_, or github_pat_, private
keys, password= strings, client_secret, and GitHub Actions expression
values such as ${{ ... }}.
Secret bindings¶
secret_bindings can describe how a secret should be mounted, but it cannot
carry a secret value or a raw provider reference:
secret_bindings:
- name: db-secret
mount:
kind: env
target: DATABASE_URL
purpose: database
required: true
rotation:
required: never
Use this only when the binding metadata is approved for the account. Each entry
needs name, mount.kind, mount.target, purpose, required, and
rotation.required. The validator accepts mount.kind: env and
mount.kind: file; rotation.required must be always or never. It
rejects value, secret_ref, key, and provider_ref inside
secret_bindings.
Public edge¶
public_edge.exposure sets the reviewed app-route exposure value:
| Exposure | Effect |
|---|---|
protected |
Forge keeps platform auth required before forwarding requests to the app. |
none |
Forge keeps the non-public route shape. |
public-redirect |
Forge keeps platform auth required. Use only when the reviewed manifest for the app requires this exact value. |
public |
Forge serves the route without platform auth. Use only for apps approved for anonymous access. |
public_edge.tier: reserved selects reserved placement for accounts approved
for that policy. Omit tier, or use free, for the default free-app
placement. Values other than reserved are normalized to free.
public_edge.allow accepts typed entries only. The supported type values are
oauth_api and admin_redirect. public_edge.review_exceptions entries must
include policy_ref and reason; scope is optional. Use these fields only
when they are part of the account's reviewed edge policy.
public_edge accepts typed policy only. Do not put WAF expressions, Cloud Armor
expressions, or provider-specific ingress expressions in the manifest.
OAuth API metadata¶
The optional oauth_api block is policy metadata for account-reviewed OAuth API
use cases:
oauth_api:
enabled: true
path: /oauth/callback
audience:
- https://api.example.internal
allowed_methods: [GET, POST]
scope:
default: read
optional: [write]
When the oauth_api block is present, include:
enabledpathscope.default
When enabled: true, manifest review also requires:
- at least one
audience - at least one
allowed_methodsentry
Unknown oauth_api fields are rejected. Do not add API keys or raw credential
material to this block.
Review exposure changes with the same care as code changes. If a customer app should require signed-in access, review the protected access policy and verify allowed and denied results. See App access and sharing for the customer-owned access controls.
Environment mapping¶
app_env records named app environments, image tags, and optional
auto-deploy ref patterns:
app_env:
preview:
branch_pattern: "^refs/heads/main$"
auto_deploy_refs:
- "refs/heads/main"
image_tag: preview
production:
branch_pattern: "^refs/(heads/release/.*|tags/release/.*)$"
auto_deploy_refs:
- "refs/heads/release/*"
- "refs/tags/release/*"
image_tag: prod
Built-in webhook intake creates deploy candidates for these refs:
refs/heads/main, refs/heads/release/*, and refs/tags/release/*. Without
manifest auto_deploy_refs, refs/heads/main targets preview, while
refs/heads/release/* and refs/tags/release/* target production.
When the manifest declares auto_deploy_refs, Forge uses those reviewed
patterns to resolve the app environment for built-in webhook candidates after it
snapshots the manifest. auto_deploy_refs does not make arbitrary refs
deployable through the built-in webhook path; use map deploy or custom CI for
refs outside the built-in webhook intake set.
Explicit deploy requests can also use
map deploy --repo <owner/repo> --env production --ref <git-ref> --installation-ref <installation-ref>.
The --env value is an app environment. It does not change the customer
account context.
Validation rules¶
Forge validates mithran.yaml before build. It rejects:
- YAML that cannot be parsed into the
map.mithran/v1manifest shape; - unknown top-level fields;
- top-level fields outside the accepted
mithran.yamlv1 schema, includingpublic_api, booleanpublic,body_size_limit_mb,roles,grants, andlive_grants; - unknown nested fields in
non_secret_env,secret_bindings,oauth_api,public_edge.allow,app_env, andapp_env.*.policy; public_edgeprovider expressions such as WAF or Cloud Armor expressions;app_enventries with emptybranch_patternorimage_tag;- secret-looking names, values, or raw secret refs in non-secret fields.
Common validation results:
| Result | Meaning | Fix |
|---|---|---|
ERR_MANIFEST_PARSE |
The YAML could not be parsed into the required manifest shape. This can include malformed YAML or missing structurally required fields. | Fix the YAML and include the required manifest fields shown in the minimal shape. |
ERR_API_VERSION or ERR_KIND |
The file is not a map.mithran/v1 MithranApp. |
Use the required header exactly as shown. |
ERR_METADATA_APP_ID or ERR_METADATA_NAME |
App identity is blank. | Set non-empty metadata.app_id and metadata.name. |
ERR_IDENTITY_PROJECT_REF |
Project identity is blank. | Set a non-empty identity.project_ref. |
ERR_CAPABILITY_* |
Capability kind, route, runtime, or startup command is missing or unsupported. | Fix capabilities[]; HTTP capabilities require route, runtime, and startup.command. |
ERR_SECRET_VALUE or ERR_SECRET_REF |
A non-secret field looks like credential material or a raw secret reference. | Remove it from the manifest and rotate exposed credentials if needed. |
ERR_PUBLIC_EDGE_* |
Edge type, exposure, allow rule, exception, or provider expression is invalid. | Use public_edge.type: platform and one supported exposure value. |
ERR_APP_ENV |
App-environment metadata is blank, or an auto-deploy ref pattern is invalid. | Set non-empty branch_pattern and image_tag for each app_env entry, and make any auto_deploy_refs entries start with refs/. |
ERR_UNKNOWN_FIELD |
A field is not in the accepted schema. | Remove the field or move that policy to the documented surface that owns it. |
Review checklist¶
Before merging a manifest change, confirm:
metadata.app_idand the served app ref are aligned for the intended hostname;identity.project_refis the correct project/app ref for the served app;- each HTTP capability has a route, runtime, and startup command;
- the process listens on
$PORT; - the repo contains a Dockerfile that builds the app started by the manifest;
non_secret_envcontains no secrets;public_edge.exposurematches the approved access model;app_envmetadata and anyauto_deploy_refsmatch the intended app environments;- release, publish, or route-impacting changes have an owner for verification.
Change impact¶
Use this table during review to decide who needs to inspect a manifest change:
| Change | Primary risk | Review owner |
|---|---|---|
metadata.app_id or app ref |
Hostname expectations change. | Developer and operator. |
identity.project_ref |
App attaches to the wrong project/app boundary. | Operator. |
capabilities[].startup.command |
Runtime starts the wrong process or exits. | Developer. |
non_secret_env or app_env.*.env_overrides |
Config drift or accidental secret exposure. | Developer. |
public_edge.exposure |
App-route exposure intent changes. | Operator. |
app_env.*.branch_pattern, auto_deploy_refs, or image_tag |
App-environment metadata, auto-deploy routing, or build-profile image tag changes. | Developer and operator. |
secret_bindings |
Secret mount metadata changes. | Operator. |
Conventions¶
- Your process must listen on
$PORTand satisfy Forge runtime readiness. The examples in these docs return HTTP 200 at/andGET /healthfor local checks. - By default, a
refs/heads/mainpush sends a GitHub App webhook that deploys topreview. - By default, a
refs/heads/release/*branch orrefs/tags/release/*tag sends a GitHub App webhook that deploys toproduction. - Reviewed
auto_deploy_refscan change app-environment resolution for those built-in webhook candidates, but cannot add new webhook intake refs. - The build comes from your
Dockerfile. The manifest declares the app; the Dockerfile builds it. - Use App access and sharing when changing
public_edge.exposure.