Files
ModelForge/docs/PROJECT_INTEGRATION.md

4.8 KiB

Integrating an application with ModelForge

The contract an application depends on is a capability, never a model, a node, a file path or a Hugging Face repository name. That is the whole design: what serves rag.embedding@1 can be replaced without the caller knowing, and the caller cannot accidentally couple to which model answered.

What your application needs to know

Three things, and nothing else:

base URL          https://modelforge.example.internal:8000
credential        the bearer token issued for your service client
capability key    rag.embedding@1

If your integration needs a model name, a revision, a node hostname or an artifact path, something has gone wrong — those are ModelForge's business, not yours.

Getting a credential

An operator creates a service client scoped to your project and the capabilities you may call:

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 credential is returned once. Only a SHA-256 hash is stored, with a short prefix for identification, so it cannot be read back — rotate if you lose it.

integration_environment is one of production, shadow, evaluation or lab.

Calling a capability

POST /api/v1/capabilities/rag.embedding@1/invoke
Authorization: Bearer mf_...
Content-Type: application/json

{"input": ["first text", "second text"]}

A successful response carries the result and an execution block describing what actually happened — queue time, inference time, whether the deployment was already warm. Use it for your own observability; do not branch on it.

Errors your integration must handle

Status Code Meaning What to do
401 CAPABILITY_NOT_AUTHORIZED Missing, invalid, revoked, expired or out-of-scope credential Do not retry; get a valid credential
429 rate limited Your client's requests-per-minute or concurrency was exceeded Back off
503 NO_ELIGIBLE_NODE No online node can serve this capability Retry with backoff; this is usually transient
503 CAPACITY_CONSTRAINED A node exists but has no headroom Retry with backoff; this is a correct refusal, not an outage
422 validation Your request body does not match the contract Fix the request

Every error response is exactly code, message and correlation_id. Log the correlation id — it is how an operator finds your request in the control-plane logs.

Scope is exact

  • rag.embedding@1 does not grant rag.embedding@2;
  • a Vision client cannot reach ASR, and an ASR client cannot reach Vision;
  • case changes, appended whitespace, a second capability in the same string and zero-width characters do not widen a scope;
  • a project-bound client cannot serve another project's binding;
  • a deprecated binding stops serving immediately.

Contract versions and migration

A capability contract version fixes the input and output schema. A change that keeps them compatible happens behind the same version. A change that does not gets a new version, and your application moves when it is ready.

The case that needs your attention is REQUIRES_REINDEX: the embedding space changed, so vectors produced by the old deployment are not comparable with the new one. ModelForge will not swap an alias underneath data that has not been reindexed, and your project binding has to declare that it supports reindex migration before such a contract can be bound. See MIGRATION_RECOVERY.md.

Batching and limits

Limit Default Setting
Inputs per invocation 8 MODELFORGE_GATEWAY_MAX_BATCH_SIZE
Characters per input 8192 MODELFORGE_GATEWAY_MAX_INPUT_CHARACTERS
Request body 64 KiB MODELFORGE_GATEWAY_MAX_PAYLOAD_BYTES
Total request time 45 s MODELFORGE_GATEWAY_REQUEST_TIMEOUT_SECONDS
Queue wait before rejection 30 s MODELFORGE_GATEWAY_QUEUE_TIMEOUT_SECONDS

Idempotency

Supply an idempotency key when a retry must not produce a second execution. Keys are unique in the database rather than in a queue, so a retry storm converges on one row regardless of which component retried — 24 concurrent requests on one key produce exactly one.

What ModelForge will never do to your application

  • serve a model you did not approve through the lifecycle;
  • swap an embedding space underneath you without a reindex;
  • fall back to a different artifact source when the recorded one is unavailable;
  • return an answer built on telemetry it knows is stale.

Each of those is a refusal with a name instead.