Documentation
ModelForgeLab is an open adapter registry. The core service — metadata, weights, fine-tune queue, and the API — can run entirely on your own hardware or via our managed hosting. No adapter data or user credentials are shared with third parties.
Optional cloud-adjacent components are available for teams that need them but are never required:
- Artifact CDN — a pull-through cache fronting
/download/*for geographically distributed teams. Your instance remains the source of truth; the CDN holds no originals. - SMS verification — the default auth flow uses a configurable
SMS provider (or can be replaced with TOTP). The core registry works without
phone verification if you disable it in
config.py. - Enterprise tier — dedicated support SLA and a managed hosting option for organisations that cannot self-host. The software and API are identical to the community edition.
Install the CLI
curl -fsSL https://modelforgelab.cloud/install.sh | sh
mfl login https://your-instance.example
The CLI stores credentials in ~/.config/mfl/credentials.json.
Pass --token to override for scripted use.
Pull an adapter
Downloads the adapter weights and verifies the sha256 checksum before writing to the local cache.
mfl pull sd15-pixelart-lora
# resolves latest version, verifies sha256, writes to ~/.cache/mfl/
mfl pull sd15-pixelart-lora --version 2.1.0 # pin a specific version
mfl pull sd15-pixelart-lora --format gguf # prefer GGUF if available
Interrupted downloads resume automatically via HTTP Range requests. You can also pull a specific base-model revision alongside the adapter:
mfl pull sdxl-watercolor-lora --with-base
Serve locally
mfl serve sd15-pixelart-lora --base runwayml/stable-diffusion-v1-5
# starts an OpenAI-compatible HTTP endpoint on localhost:11434
mfl serve qwen25-7b-support-tone --port 9000 --workers 2
The serve command loads the base model, attaches the adapter, and exposes a
/v1/completions (text) or /v1/images/generations
(image) endpoint compatible with standard clients.
Fine-tune with LoRA
Upload a JSONL dataset, choose a base model and rank, and queue a run. Progress streams over server-sent events; the resulting adapter lands in your private registry automatically.
mfl finetune \
--base Qwen/Qwen2.5-7B-Instruct \
--data ./train.jsonl \
--rank 16 --alpha 32 \
--epochs 3 --seed 42
Dataset format — one JSON object per line:
{"prompt": "Summarise this ticket:", "completion": "User reports login error on Safari 17."}
{"prompt": "Summarise this ticket:", "completion": "Payment declined after promo code applied."}
Training runs are isolated per-job. You can monitor live loss curves in the UI or stream them via the API:
curl -N -H "Authorization: Bearer $MFL_TOKEN" \
https://your-instance.example/events/<job_id>
Formats & precision
| Format | Typical precision | Compatible runtimes |
|---|---|---|
| safetensors | fp16 / bf16 | transformers, diffusers, vLLM |
| gguf | q4_k_m, q5_k_m, q8_0 | llama.cpp, Ollama, LM Studio |
| diffusers | fp16 | ComfyUI, Automatic1111 |
The registry stores the format and precision in adapter metadata. mfl pull
downloads the correct file automatically. To request a specific format:
mfl pull llama3-8b-changelog-writer --format gguf --precision q4_k_m
Authentication
Public adapters can be pulled without credentials. Members-only adapters and all write operations require a valid session token.
Generate a long-lived API token under Account → API tokens. Tokens are scoped:
| Scope | Allowed operations |
|---|---|
read | Pull public and members-only adapters, list catalog |
write | Upload datasets, queue fine-tune jobs, push adapters |
admin | Manage users, change adapter visibility, delete artifacts |
export MFL_TOKEN=mfl_live_xxxxxxxxxxxxxxxxxxxx
mfl pull flux-linework-lora # members-only, uses token from env
Python SDK
Install alongside the CLI or standalone. The SDK is distributed via the CLI installer and also available as a wheel in each GitHub release:
pip install mfl/modelforge_sdk-*.whl # from a downloaded release
from modelforge import Client
client = Client("https://your-instance.example", token="mfl_live_xxx")
# List all public adapters
for adapter in client.adapters.list(public=True):
print(adapter.slug, adapter.version)
# Pull and load with PEFT
adapter_path = client.adapters.pull("qwen25-7b-support-tone")
from transformers import AutoModelForCausalLM
from peft import PeftModel
base = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-7B-Instruct")
model = PeftModel.from_pretrained(base, adapter_path)
Configuration
All settings are controlled via environment variables. No config file required.
| Variable | Default | Description |
|---|---|---|
MFL_SECRET_KEY | — | Required. Random secret for session signing. |
MFL_UPLOAD_ENABLED | true | Allow dataset uploads. |
MFL_MAX_UPLOAD_BYTES | 5368709120 | Upload size limit (5 GB default). |
MFL_STREAM_BLOCK_BYTES | 1048576 | Streaming block size for downloads. |
MFL_DOWNLOAD_RATE_MBPS | 0 | Throttle downloads (0 = unlimited). |
MFL_MAX_CONCURRENT_SSE | 10 | Max simultaneous SSE streams. |
Rate limits
Default limits apply per IP address (requires MFL_TRUST_XFF=true
when behind a reverse proxy):
| Endpoint group | Limit |
|---|---|
| Page requests | 120 / minute |
Downloads (/download/*) | 20 / minute |
Uploads (/upload) | 5 / minute |
SSE streams (/events/*) | 10 concurrent |
API (/v1/*) | 300 / minute |
Exceeding a limit returns 429 Too Many Requests. Limits reset
on a rolling 60-second window.