114 lines
4.7 KiB
Markdown
114 lines
4.7 KiB
Markdown
# 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).
|