# First run You have a healthy control plane. Nothing is serving yet, and that is correct — this page is how you get from there to a capability an application can call. ## What you have after installation | | | | --- | --- | | Projects | seeded from the shipped manifests | | Capability contracts | **none** | | Capability deployments | **none** | | Model candidates | seeded as a discovery list, none approved | | Policies | lifecycle, migration, observability and recovery defaults present | | Compute nodes | none until you enrol one | Contracts and deployments are absent on purpose. A contract is lifecycle-owned, and a deployment requires a model artifact that has been acquired, verified and promoted. ModelForge will not fabricate either from a manifest, so the bindings that are waiting for a contract are *reported* rather than invented: ```text SYNCED project registry 8 binding(s) waiting for a contract ``` ## 1. Enrol a compute node Nothing can serve without a node. See [NODE_AGENT.md](NODE_AGENT.md) for the full procedure. In short: ```bash curl -s -X POST -H "X-ModelForge-Admin-Token: $KEY" -H "Content-Type: application/json" \ -d '{"display_name":"GPU Node","expires_in_seconds":900}' \ http://127.0.0.1:8000/api/v1/admin/node-enrollments ``` The token it returns is **single use**. A concurrent storm against one token produces exactly one identity and one credential — that is enforced by an atomic claim, not by timing. Give the token to the agent on the GPU host and start it. The node appears with liveness `online`. ## 2. Discover a model candidate The Discover workspace lists the candidates in `config/models/initial-candidates.yaml`. Nothing in that file is approved by being listed — it is a starting point for verification. ## 3. Acquire and verify the artifact Acquisition downloads into quarantine, records a per-file SHA-256, and runs the supply-chain checks before anything is promoted to the verified artifact root. `trust_remote_code` is never enabled; production refuses to start if it is. An artifact that fails verification stays in quarantine. That is the system working. ## 4. Register a capability contract and promote a deployment Capabilities are the interface applications bind to. A contract fixes the input and output schema for a version; a deployment is a specific artifact set and runtime profile serving that contract. Promotion runs through the lifecycle: plan, approval, execution, and an immutable snapshot that lets an interrupted operation roll back exactly once. `no_hidden_auto_promotion` asserts that no production deployment exists without a recorded production approval — there is no path that quietly promotes something. See [MODEL_LIFECYCLE.md](product/MODEL_LIFECYCLE.md). ## 5. Create a service client for the application ```bash curl -s -X POST -H "X-ModelForge-Admin-Token: $KEY" -H "Content-Type: application/json" \ -d '{"name":"examplerag-production","allowed_capabilities":["rag.embedding@1"], "project_key":"examplerag","integration_environment":"production", "purpose":"ExampleRAG production embedding"}' \ http://127.0.0.1:8000/api/v1/admin/service-clients ``` The response carries the credential **once**. Only a SHA-256 hash is stored, with a bounded prefix for identification. There is no way to read it back — rotate if you lose it. ## 6. Call the capability ```bash curl -s -X POST -H "Authorization: Bearer $CREDENTIAL" -H "Content-Type: application/json" \ -d '{"input":["the text to embed"]}' \ http://127.0.0.1:8000/api/v1/capabilities/rag.embedding@1/invoke ``` The application names a **capability**, never a model, a node or a file path. That is the whole point of the platform: you can replace what is behind `rag.embedding@1` without the caller knowing, and the caller cannot accidentally depend on which model answered. See [PROJECT_INTEGRATION.md](PROJECT_INTEGRATION.md). ## What you should see when it is working | Signal | Healthy value | | --- | --- | | `/api/v1/health/ready` | 200 | | Node liveness | `online` | | `/api/v1/capabilities` | your contract listed | | Operations overview | no firing alerts | | Recovery dashboard | a recent verified backup, no unprotected assets | ## Common first-run outcomes | What you see | What it means | | --- | --- | | `503 NO_ELIGIBLE_NODE` | No online node can serve this capability. Check node liveness first. | | `CAPACITY_CONSTRAINED` | A node exists but has no headroom. This is a correct refusal, not an error. | | `401 CAPABILITY_NOT_AUTHORIZED` | The credential is missing, revoked, expired, or not scoped to this capability. | | `8 binding(s) waiting for a contract` | Expected before you have promoted anything. | More in [TROUBLESHOOTING.md](TROUBLESHOOTING.md).