Skip to content

Quickstart

Use this guide to take a small HTTP app from a fresh GitHub repo to a Forge production app URL.

The example uses Node and a Dockerfile. The same deploy path works for any language that follows the HTTP app contract: build from a repo-root Dockerfile, listen on $PORT, and satisfy Forge runtime readiness. The sample app also includes GET /health.

This guide is currently blocked before onboarding. No customer-supported signed Aegis package is published, and aegis setup does not create the Map login state required by map onboard. The current limitation is documented below; the remaining steps are not a runnable customer path.

What you need

Before you start:

  • an Apple Silicon Mac; no customer-supported signed Aegis package is published today, so this guide cannot be started from its install step;
  • OpenAI Codex CLI (codex) and Lima with limactl on your PATH;
  • Docker if you want to run the local container check before deploy;
  • a GitHub repo you can push to;
  • permission to install or request installation of the Forge GitHub App for that repo;
  • the GitHub App installation ref for the customer account;
  • tenant, account, and app/project refs when your account operator requires them.

Current limitation: Aegis writes account state under ~/.aegis/local/state/account/session.private.json. Map reads ~/.config/mithran/login.json and requires map_control_endpoint plus the map-control audience. map login save needs an endpoint and token that aegis setup does not provide, so no shipped bridge exists and the onboarding flow shown here is blocked.

If you administer the GitHub organization, tenant, or security review for the account, read Administer Forge and Security and Trust before granting repository access.

Use these values throughout the guide:

Value Replace with
<owner/repo> Your GitHub repo, such as acme/forge-hello.
<app_id> DNS-friendly app ID, usually the repo name.
<app-ref> Served app ref for onboarding, route, version, and publish commands, usually app:<app_id>.
<installation-ref> GitHub App installation ref for the customer account.

For the shortest path, choose <app_id> as the repo name and use <app-ref> as app:<app_id>. Onboarding accepts --app-ref for this value and stores it in identity.project_ref because the manifest field has that name. Use the same served app ref in map versions and map publish. If your operator gives you different tenant, account, or app/project refs, use those values consistently.

1. Install the CLI

No customer-supported signed Aegis package is published today. Dogfood prerelease .pkg assets are not customer installs, so this quickstart cannot proceed through the install step. See Install the CLI for the current package status; the remaining steps are reference for the intended Forge workflow.

2. Sign in and connect GitHub

From the local checkout whose origin points at <owner/repo>, run setup and then prove the repo grant explicitly:

aegis setup
aegis doctor --json
aegis github status --project-repo <owner/repo> --require --json

If the CLI gives you a GitHub setup link, use that link instead of going directly to GitHub's App page; the setup link ties the GitHub installation back to your Mithran setup profile. The repo-scoped grant check above proves whether the target repo is actually covered.

If GitHub requires an org owner, ask the owner to approve or install the App and grant the repo. See Connect GitHub.

3. Create the app files

From your local repo checkout, create a tiny HTTP app:

package.json
{
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {}
}
server.js
const http = require("http");

const port = Number(process.env.PORT || 8080);

http.createServer((req, res) => {
  if (req.url === "/health") {
    res.writeHead(200, { "content-type": "text/plain" });
    res.end("ok");
    return;
  }

  res.writeHead(200, { "content-type": "text/html" });
  res.end("<h1>Hello from Forge</h1>");
}).listen(port, "0.0.0.0");
Dockerfile
FROM node:22-alpine
WORKDIR /app
COPY package.json ./
COPY server.js ./
ENV PORT=8080
CMD ["npm", "start"]

4. Add mithran.yaml

Create mithran.yaml at the repo root:

mithran.yaml
apiVersion: map.mithran/v1
kind: MithranApp
metadata:
  app_id: <app_id>
  name: Forge Hello
identity:
  project_ref: <app-ref>
capabilities:
  - kind: http
    route: /
    runtime: nodejs22
    startup:
      command: npm start
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

Replace <app_id> with a short DNS-friendly label and <app-ref> with the served app ref you will use for onboarding, versions, and publishing, usually app:<app_id>. The clean public URL uses the app ref label after you publish:

https://<app_id>.apps.mithran.cloud/

For the full manifest field list, see mithran.yaml reference.

5. Check the app locally

Build and run the same container shape Forge will build:

docker build -t forge-quickstart .
docker run --rm -p 8080:8080 -e PORT=8080 forge-quickstart

In another terminal:

curl -i http://localhost:8080/health
curl -i http://localhost:8080/

Expected result:

  • /health returns HTTP 200;
  • / returns Hello from Forge;
  • the container keeps running until you stop it.

If this fails locally, fix it before deploying. Forge checks the same app contract at runtime.

6. Commit the app

Commit the app files locally:

git add package.json server.js Dockerfile mithran.yaml
git commit -m "Add Forge quickstart app"

The GitHub repo must already exist and be granted to the Forge GitHub App shown by the customer setup link. If the remote repo does not exist yet, create it in GitHub first, then add it as origin with the URL GitHub provides.

Confirm the local checkout points at the repo and set the local branch name before onboarding or pushing deploy refs:

git remote -v
git branch -M main

7. Onboard the repo

The onboarding command below is blocked after aegis setup because no shipped step creates the Map login state it requires. See the current limitation above.

Run onboarding from the same checkout. If <app-ref> is app:<repo-name>, you can omit --app-ref because that is the CLI default:

map onboard --installation-ref <installation-ref> <owner/repo> --repo-dir .

Onboarding registers the repo with Forge and leaves your existing mithran.yaml in place. Run it before pushing deploy refs so the webhook can resolve the repo registration when the push arrives. The quickstart uses built-in GitHub App webhooks, so no repo workflow is required.

Expected text output is shaped like this:

onboarded <owner/repo> (repo registration recorded).
app identity: <app-ref> (stored as identity.project_ref; used for deploy routing, versions, and publish).
next: commit + push mithran.yaml, then push a release/* ref (or tag) — the webhook deploys (no repo workflow needed).

If onboarding wrote a starter manifest, the output also includes wrote ./mithran.yaml. This quickstart already created mithran.yaml, so the CLI should not overwrite it.

If your operator gave you tenant, account, or app/project refs, pass them now. Use the served app ref that should own the app's route, versions, publish pointer, and access context:

map onboard \
  --installation-ref <installation-ref> \
  --tenant-ref <tenant-ref> \
  --account-ref <account-ref> \
  --app-ref <app-ref> \
  <owner/repo> \
  --repo-dir .

Confirm the registration:

map doctor --app <owner/repo>

map doctor --app adds route and recent-deploy diagnostics when those records exist. It does not list the full onboarding record directly, so keep the map onboard output with the app's repo registration record.

For onboarding details and custom-CI options, see Onboard a repo.

8. Push preview

Push main to start the built-in preview deploy:

git push -u origin main

Forge receives the GitHub App webhook for refs/heads/main, verifies the installation and repo grant, snapshots the source, and targets the preview app environment.

Webhook deploys do not print a deployment ref in your terminal. After the deploy starts, use the route view to discover the recorded deployment refs for the app:

map versions <app-ref>

If internal versions is still empty, wait a few seconds and run the command again. Copy a deployment ref from internal versions or from the preview alias, then inspect it:

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

9. Deploy a release

Create and push a release branch:

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

That push sends another GitHub App webhook to Forge. The built-in webhook policy maps refs/heads/release/* to the production app environment. Forge checks the repo registration, snapshots source, reviews the manifest and source snapshot, builds the image, starts the runtime, programs the route, and records deploy evidence.

List versions again and copy the release deployment ref from the production alias or internal versions section:

map versions <app-ref>

Use status and evidence to inspect that release deploy:

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

See Deploy status and evidence for the field list and evidence model.

10. Publish the clean public URL

List the versions for your app:

map versions <app-ref>

Copy the version label that points at the reviewed release deployment ref, then publish that version:

sha=$(git rev-parse HEAD)
map publish <app-ref> --version <version-from-output> --expected-sha "$sha"

--expected-sha tells Forge to move the clean public URL only if the selected version still records the source SHA you reviewed.

Check the published hostname:

curl -i https://<app_id>.apps.mithran.cloud/

The quickstart manifest uses public_edge.exposure: protected, so anonymous curl should reach the Forge auth boundary rather than the app body. Open the same URL in a signed-in browser session to reach the Hello from Forge page.

Success checkpoints

Use these checkpoints before moving on. They keep source access, deploy state, publishing, and app behavior separate.

Step Continue when If it does not match
GitHub grant aegis github status --project-repo <owner/repo> --require --json exits successfully for the target repo. Finish the GitHub App grant through the customer setup link, then run the same command again.
Local app / and /health return HTTP 200 from the local container. Fix the Dockerfile, startup command, $PORT binding, or app readiness behavior before deploy.
Onboarding map onboard prints that the repo was onboarded and records the repo registration. Re-check the installation ref, repo grant, tenant/account/project refs, and map onboard output.
Preview deploy map versions <app-ref> shows a preview alias or internal version with a deployment ref, and map --json status <deployment-ref> shows deployment.status.status: Succeeded. Use map --json evidence <deployment-ref> and the failed status field to decide whether the fix is source, manifest, build, runtime, or route.
Release deploy map versions <app-ref> shows a production alias or internal version for the release branch deployment, and map --json status <deployment-ref> shows deployment.status.status: Succeeded. Confirm the pushed ref is refs/heads/release/*, the repo is still granted and onboarded, and the deploy status identifies the failed stage.
Publish map publish prints published https://..., and map versions <app-ref> shows a published line for the same deployment ref. Re-run map versions, choose a reviewed internal version that reached Succeeded or Promoted, and use --expected-sha for the commit you reviewed.
Public URL The published hostname no longer returns unknown_hostname; anonymous curl is denied before the app runtime, and a signed-in browser can reach the app. Confirm the published record, app ref, app hostname, deployed metadata.app_id, exposure, and route status.

What happened

flowchart LR
  A[map onboard] --> B[Repo registration]
  B --> C[git push main or release/v1]
  C --> D[GitHub App webhook]
  D --> F[Forge control plane]
  F --> G[Snapshot source]
  G --> H[Review manifest and source snapshot]
  H --> I[Build image]
  I --> J[Start runtime]
  J --> K[Program route]
  K --> L[Record version and evidence]
  L --> M[map publish]
  M --> N[Clean public URL]

No Forge deploy secret is stored in your repo. Built-in deploys are authorized through the Forge GitHub App grant, the active connector for the installation, and the repo onboarding record. Publishing is a separate step that pins the clean public URL to one reviewed version that reached Succeeded or Promoted. More on the model: How Forge works.

If something fails

Symptom Start here
Setup or GitHub install does not complete. Connect GitHub and Troubleshooting.
map onboard returns an API error. Confirm the repo slug, installation ref, setup context, app ref, and GitHub App grant, then see Onboard a repo.
No deploy starts after the release push. Webhook deploy does not start.
Build fails. Build fails.
Runtime never becomes ready. Runtime readiness fails / the app won't come up.
The public URL returns unknown_hostname. Route propagation.
The URL still shows an older version. Versions and publishing.

Next