FORGE-200 — The Forge Runtime

FORGE-200 — The Forge Runtime

Project Forge — First Execution Document Status: Normative for execution. Implements FORGE-100 and FORGE-101; introduced by Capability 7A. Precedence: the constitutional corpus (FORGE-001 … FORGE-103) governs. This document does not amend the constitution; it explains and binds how the constitution executes. Where a reading of this document contradicts FORGE-101, FORGE-101 governs. Historical note (Capability 7C, FORGE-202): this document was written while the runtime’s first organism, Mjolnir, was still declared in this repository at instances/mjolnir. FORGE-201 records why and how that organism moved into its own repository, forge-mjolnir; FORGE-202 records the completed engine-side cleanup. Every mechanism described below is unchanged by the move — the runtime never knew Mjolnir’s name — only the path in Part 2’s step 1 (instances/mjolnir) and the publication path in Part 5’s example (public/mjolnir/…) now name a directory that lives in Mjolnir’s repository, not this one.


Preamble

The constitutional corpus is complete: FORGE-101 defined the three planes — Core, Domain, Instance — and declared that Forge is a runtime, not a framework. What remained undefined was the machinery itself: the concrete thing that takes one instance’s declaration, composes it with the engine and its domains, and produces a living organism.

This document is the canonical explanation of how Forge executes. It documents the Forge Runtime as implemented in forge-core/runtime and the contracts it composes against — proven, at the time of writing, by composing the first Forge Instance, Mjolnir, from inside this repository. Mjolnir has since moved to its own repository (FORGE-201); the runtime’s mechanics below are exactly as they were, because nothing in them ever named it.

One sentence carries the whole document:

Project Forge is the engine; a Forge Instance is a living organism; the runtime is the act of composing the second out of the first — and the engine never learns the organism’s name.

And one principle governs how the engine is allowed to grow:

Adding a capability means adding a manifest, never editing the engine.

Every rule in this document exists in service of one or the other of these two sentences.


Part 1 — Engine vs Instance

The engine is everything under forge-core and the domain packages (forge-hpc, and its successors). It is the machinery of truth-keeping, publication, and presentation, plus the expertise of each scientific practice. The engine is reused by every deployment and owned by the Forge project and its domain communities.

An instance is one real deployment: Mjolnir today; Rubus, BioHPC, or another university’s cluster tomorrow. An instance is pure declaration (FORGE-101 Part 5.2): one forge-instance.json manifest carrying identity, branding, enabled capabilities, domain settings, and runtime options — and no logic. Every line an instance contains is a line the next adopter cannot reuse, so the architecture succeeds exactly insofar as instances approach pure declaration.

The prohibition that makes this real, restated from FORGE-101 Part 2.3 and now enforced by test:

The name of any instance appearing anywhere in engine code is a build failure. The engine knows that instances exist; it never knows which.

Mjolnir is therefore not “the product with a config file.” Mjolnir is a document the engine reads. Deleting instances/mjolnir leaves the engine whole; deleting any engine capability leaves Mjolnir a smaller organism, not a broken one.

Mjolnir is also not an analytics platform with a runtime bolted on. Analytics — like Queue Insights, Scheduler, or Storage — is one capability an organism may enable among many; it is not the organism’s identity. An instance’s wordmark names the organism, not the capability that happened to come first.

Part 2 — The Runtime

The Forge Runtime (forge-core/runtime) is the composition machinery of FORGE-101 Part 7.4, implemented. Its execution sequence:

1. LOAD       the instance manifest (forge-instance.json)
2. VALIDATE   identity: required fields, types, unknown keys fail loudly
3. DISCOVER   capability registrations (forge-capability.json) under the
              composition's declared roots — declaratively, at composition
              time; no runtime plugin scanning
4. RESOLVE    the instance's enabled capability ids against the registry;
              unknown ids and undeclared domains fail composition
5. DERIVE     navigation and the runtime identity document as pure
              functions of (identity × resolved registrations)
6. PUBLISH    the identity document into the instance's publication
              namespace: public/<namespace>/identity.json, stamping the
              moment of writing as the document's generation timestamp

Steps 1–4 are composition: pure validation, failures cheap and loud, no truth touched. Steps 5–6 are projection: deterministic, regenerable, drift-detectable — with one deliberate exception. The identity content DERIVE produces (Part 4) is a pure function of (identity × resolved registrations): re-deriving it from an unchanged declaration is byte-identical, forever. PUBLISH then wraps that content in a thin envelope recording when the wrapping happened. Only the envelope varies between runs; the test suite checks that everything else does not, and that a published document’s envelope is well-formed even when its timestamp cannot be reproduced by definition.

The runtime is a publication runtime (FORGE-101 Part 1.1): it runs at build time and emits static artifacts. Nothing in this document introduces a request-serving process.

Part 3 — The Organism Lifecycle

This is the canonical mental model for how Forge executes, from cold start to a serving organism:

Forge Runtime
   ↓
Load Instance
   ↓
Validate Identity
   ↓
Discover Capabilities
   ↓
Resolve Contracts
   ↓
Compose Publications
   ↓
Publish Organism
   ↓
Living Instance

Each conceptual stage is one or more of the concrete steps in Part 2:

Lifecycle stage Part 2 step(s) What happens
Load Instance LOAD The instance’s forge-instance.json is read from disk.
Validate Identity VALIDATE Required fields, types, and unknown keys are checked; failures are loud and typed.
Discover Capabilities DISCOVER Every forge-capability.json under the composition’s declared roots is found and validated.
Resolve Contracts RESOLVE The instance’s enabled capability ids are matched against discovered registrations; domain capabilities are checked against declared domains.
Compose Publications DERIVE Navigation and the runtime identity document are built as pure functions of the resolved composition.
Publish Organism PUBLISH The identity document is written into the instance’s publication namespace, stamped with the moment of writing.
Living Instance The published organism: one identity, one namespace, one navigation, reachable at its declared hosts.

Nothing above is domain- or instance-specific. The same seven steps compose Mjolnir today and will compose the second organism tomorrow (Part 7) — which is the whole point of writing them down once, here, instead of once per deployment.

Part 4 — Identity

An instance identity is the validated form of forge-instance.json:

Field Meaning Plane of the value
id permanent instance identifier (kebab-case) instance
name display name instance
institution the operating institution instance
hosts one or more public addresses this organism answers to instance
publication_namespace namespace under public/ (defaults to id) instance
timezone IANA timezone, validated instance
version optional organism version, informational instance
branding wordmark, logo, theme tokens, URLs instance
capabilities enabled capability ids — selection, not authorship instance
runtime_options named booleans for staged behaviour instance
domains per-domain settings, opaque to Core domain vocabulary, instance values

Two structural rules protect the planes:

hosts is a list, not a scalar, by design. The runtime assumes no single canonical address: during a migration an organism may answer at several hosts simultaneously — its permanent home, a legacy alias still in DNS, a path-scoped mount on another domain. Nothing downstream treats hosts[0] as more canonical than its siblings; a future need to distinguish a primary address is a field to add, not a redesign.

runtime_options replaces what earlier drafts called feature_flags. The rename is deliberate: “feature flag” invites an ever-growing, never-retired catalogue of permanent toggles. runtime_options names the same mechanism — booleans an instance declares to stage behaviour — while keeping the expectation that each entry is temporary scaffolding for a rollout, reviewed and removed once the behaviour it stages is simply how the organism works. public-organism (Part 7) is the first and, for now, only entry.

The runtime projects the identity into the runtime identity documentpublic/<namespace>/identity.json — the one artifact through which reader-facing surfaces learn who they are serving:

{
  "runtime": {
    "schema_version": "…",
    "runtime_version": "…",
    "instance_version": "…",
    "status": "draft | published",
    "generated_at": "…"
  },
  "instance": {
    "id": "…",
    "name": "…",
    "organization": "…",
    "hosts": [ "…" ],
    "theme": { "accent": "…" },
    "features": [ { "id": "…", "title": "…", "path": "/…/" } ],
    "capabilities": [  ],
    "runtime_options": {  }
  }
}

The runtime block describes the Forge Runtime and the publication act itself — engine and schema versions, the organism’s own declared version (when it declares one), whether this is a draft or a live publication, and when this document was generated — never scheduler or domain state; that distinction is what keeps this block Core’s to own. schema_version and runtime_version are engine constants (Part 2); instance_version, when present, is a value the instance manifest declares about itself. status and generated_at are the only fields not determined solely by the declaration — status follows the public-organism runtime option, and generated_at is stamped once, at the moment PUBLISH writes the file (Part 2).

The frontend consumes this document and nothing else. No page, stylesheet, or script in the engine carries an instance’s name, colours, institution, or URLs; static markup may carry a fallback rendering of the published document, never an independent statement. Branding flows in exactly one direction: declaration → runtime → document → surface.

Part 5 — Publication namespaces

Every published artifact belongs to exactly one instance namespace:

public/mjolnir/…      Mjolnir's truth
public/rubus/…        a future organism's truth

The namespace is the publication-time face of FORGE-100 Part 4.1’s instrument-scoped identifiers: two organisms can never collide, and federation later requires no redesign. PublicationNamespace places artifacts (public/<namespace>/<relative>), rejecting absolute paths and .. segments; an artifact cannot escape its organism.

Compatibility. Artifacts published before namespaces existed remain addressable. The LegacyPathBridge canonicalises an un-namespaced public/… path into the default instance’s namespace, and passes already-namespaced paths through unchanged. Old addresses keep resolving; new artifacts are born namespaced. Nothing breaks, and the bridge is the only place that needs to know the old form ever existed.

Part 6 — Capability registration

A capability is a major subsystem’s self-declaration to the runtime: Queue Insights, Software Intelligence, Scheduler, Storage, Telemetry, Reservations, Node Intelligence, Publication, and their successors.

Each capability ships a forge-capability.json beside its code:

{
  "id": "queue-insights",
  "title": "Queue Insights",
  "plane": "domain",
  "domain": "hpc",
  "summary": "…",
  "owner": "…",
  "navigation": { "order": 10, "path": "/queues/" },
  "version": "…"
}

The rules, each carrying its FORGE-101 obligation:

Part 7 — The organism

A composed instance is a living organism: one identity, one publication namespace, one set of enabled capabilities, one derived navigation — publishing its own truth on its own cadence, under its own name, at its own addresses.

The architecture already supports serving one organism cleanly at its declared hosts (Part 4): everything the organism’s surfaces need lives under public/<namespace>/, keyed off one identity document, with branding and navigation derived at composition time. DNS and deployment are deliberately out of scope; the public-organism runtime option stages the transition, and turning it on will be a recorded act, not a code change.

Because organisms are declarations, multiplying them is cheap by construction: a second instance is a second forge-instance.json plus a second namespace. Nothing in the engine changes, which is the entire point — and, per FORGE-101 Part 16.6, the second organism is the acceptance test of the first’s architecture.

Part 8 — What this document binds