Developer Cookbook
Practical recipes for integrating MatrixAI into your own code. Each section shows a complete, runnable example — Python, curl, and CLI — covering the full development workflow from training to production.
matrixai package — it is pre-installed inside the Studio Docker container. Run CLI commands with docker exec matrixai matrixai <command>.MatrixAI exposes two HTTP surfaces that you interact with from code:
http://localhost:8080/api/ when Studio is running. Use this for training jobs, playground, and model management from the browser or scripts.matrixai serve after training. This is what your application calls in production.Start a production server from a trained model:
# Inside the Studio container (models live in /data/): docker exec matrixai matrixai serve /data/my_model.mxai \ --params /data/my_model_params.json \ --api-key "$(openssl rand -hex 20)" \ --port 9000 \ --host 0.0.0.0
- "9000:9000" under matrixai: ports: in docker-compose.yml.Or run it locally if you have pip install matrixai-core:
matrixai serve model.mxai --params params.json --api-key secret123 --port 9000
All write endpoints require Authorization: Bearer <api-key>. The key is set when you start the server. You can also supply a read-only key for prediction-only clients.
# curl — health (no auth needed)
curl http://localhost:9000/api/v1/health
# → {"ok": true}
# curl — predict with auth
curl -X POST http://localhost:9000/api/v1/predict \
-H "Authorization: Bearer secret123" \
-H "Content-Type: application/json" \
-d '{"features": [0.7, 1.2, 0.3, 2.1]}'Python client setup (reuse this in every recipe):
import requests
BASE = "http://localhost:9000"
API_KEY = "secret123"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
# Health check
r = requests.get(f"{BASE}/api/v1/health")
r.raise_for_status()
print(r.json()) # {"ok": true}Two-key setup — read-only key for prediction clients, write key for CI:
matrixai serve model.mxai \ --api-key "write-key-here" \ # full access --api-key-read "read-only-key" \ # predictions only --port 9000
403.Error schema — every error response has the same shape:
{
"error": true,
"code": "UNAUTHORIZED",
"message": "Missing or invalid Authorization header"
}POST /api/v1/predict accepts either a single object or an array. Sending an array returns a list of results in the same order.
Single prediction:
import requests
def predict(features: list[float]) -> dict:
r = requests.post(
f"{BASE}/api/v1/predict",
headers=HEADERS,
json={"features": features},
timeout=10,
)
r.raise_for_status()
return r.json()
result = predict([0.7, 1.2, 0.3, 2.1])
print(result)
# → {"prediction": "spam", "confidence": 0.94, "probabilities": {"spam": 0.94, "not_spam": 0.06}}Batch prediction:
def predict_batch(rows: list[list[float]]) -> list[dict]:
payload = [{"features": f} for f in rows]
r = requests.post(
f"{BASE}/api/v1/predict",
headers=HEADERS,
json=payload,
timeout=30,
)
r.raise_for_status()
return r.json()
results = predict_batch([
[0.7, 1.2, 0.3, 2.1],
[1.5, 0.8, 1.1, 0.4],
[2.3, 0.2, 0.9, 1.8],
])
# → [{"prediction": "spam", ...}, {"prediction": "not_spam", ...}, ...]Robust client with error handling:
import requests
from requests.exceptions import HTTPError, Timeout
class MatrixAIClient:
def __init__(self, base_url: str, api_key: str):
self.base = base_url.rstrip("/")
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
})
def health(self) -> bool:
try:
r = self.session.get(f"{self.base}/api/v1/health", timeout=5)
return r.ok and r.json().get("ok") is True
except Exception:
return False
def predict(self, features: list[float]) -> dict:
r = self.session.post(
f"{self.base}/api/v1/predict",
json={"features": features},
timeout=10,
)
if r.status_code == 401:
raise PermissionError("Invalid API key")
if r.status_code == 422:
raise ValueError(f"Bad payload: {r.json()}")
r.raise_for_status()
return r.json()
def predict_batch(self, rows: list[list[float]]) -> list[dict]:
payload = [{"features": f} for f in rows]
r = self.session.post(
f"{self.base}/api/v1/predict",
json=payload,
timeout=60,
)
r.raise_for_status()
return r.json()
# Usage
client = MatrixAIClient("http://localhost:9000", "secret123")
assert client.health(), "Server not reachable"
print(client.predict([0.7, 1.2, 0.3, 2.1]))Available endpoints at a glance:
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/health | Liveness check — no auth required |
| POST | /api/v1/predict | Single or batch inference |
| GET | /api/v1/registry | List models in registry |
| POST | /api/v1/registry/push | Push a trained model to registry |
| GET | /api/v1/registry/:name/:ver | Pull a specific model version |
| POST | /api/v1/registry/:name/:ver/predict | Predict from a registry model |
| DELETE | /api/v1/registry/:name/:ver | Remove a model version |
| POST | /execute-action | Run an audited action (requires --contract) |
| GET | /openapi.json | OpenAPI spec |
| GET | /docs | Interactive API docs |
The training workflow lives in the CLI. Use docker exec to run it inside the Studio container where your models and data are stored.
Step 1 — generate a model from a prompt:
# Generates model.mxai + model.mxtrain template inside the container docker exec matrixai matrixai generate supervised \ "classify emails as spam or not spam based on word count, link count, sender score and hour sent" # Output files (inside container at /data/): # my_model.mxai — model architecture # my_model.mxtrain — training configuration
Step 2 — train with your CSV:
# Copy your data into the container docker cp emails.csv matrixai:/data/emails.csv # Train docker exec matrixai matrixai train supervised \ --model /data/my_model.mxai \ --dataset /data/emails.csv # Output files written to the same directory: # params.json — trained weights # training_trace.json — epoch losses, best epoch, backend info # evaluation_report.json — accuracy / confusion matrix
Step 3 — evaluate on a hold-out set:
docker exec matrixai matrixai evaluate \
--model /data/my_model.mxai \
--params /data/params.json \
--dataset /data/test_emails.csv
# JSON output:
# {
# "accuracy": 0.94,
# "confusion_matrix": [[480, 20], [12, 488]],
# "rows": 1000,
# "is_regression": false
# }mae, rmse, and r2 instead of accuracy.Read training output from Python:
import json, subprocess
# Read training_trace.json from the container
result = subprocess.run(
["docker", "exec", "matrixai", "cat", "/data/training_trace.json"],
capture_output=True, text=True, check=True,
)
trace = json.loads(result.stdout)
print(f"Best epoch: {trace['best_epoch']}")
print(f"Final loss: {trace['epochs'][-1]['loss']:.4f}")
print(f"Backend: {trace['backend']}")Generate a synthetic dataset (useful when you don't have data yet):
docker exec matrixai matrixai generate-dataset \ --model /data/my_model.mxai \ --training /data/my_model.mxtrain \ --rows 500 \ --seed 42 \ --mode coherent # or: random (pure noise) # Writes emails_synthetic.csv + manifest with origin=synthetic
The registry versioned model store. Push trained models after evaluation, pull them from any environment, and serve directly from registry without copying files around.
Push a trained model:
# CLI
docker exec matrixai matrixai registry push my-spam-detector \
--run-dir /data/ # directory containing params.json + training_trace.json
# HTTP equivalent
curl -X POST http://localhost:9000/api/v1/registry/push \
-H "Authorization: Bearer secret123" \
-H "Content-Type: application/json" \
-d '{"name": "my-spam-detector", "run_dir": "/data/"}'List and inspect models:
# List all models docker exec matrixai matrixai registry list docker exec matrixai matrixai registry list --json # machine-readable docker exec matrixai matrixai registry list --name spam # filter by name prefix # Show full manifest docker exec matrixai matrixai registry show my-spam-detector # Verify integrity (exit 0 = OK, non-zero = tampered) docker exec matrixai matrixai registry verify my-spam-detector
Python — list and pull via HTTP:
import requests
BASE = "http://localhost:9000"
HEADERS = {"Authorization": "Bearer secret123"}
# List models
r = requests.get(f"{BASE}/api/v1/registry", headers=HEADERS)
models = r.json() # [{name, version, model_hash, ...}, ...]
print(f"Registry has {len(models)} model(s)")
# Pull a specific version
r = requests.get(f"{BASE}/api/v1/registry/my-spam-detector/1.0", headers=HEADERS)
manifest = r.json()
# Predict directly from registry (no local file needed)
r = requests.post(
f"{BASE}/api/v1/registry/my-spam-detector/1.0/predict",
headers={**HEADERS, "Content-Type": "application/json"},
json={"features": [0.7, 1.2, 0.3, 2.1]},
)
print(r.json())Compare two model versions:
docker exec matrixai matrixai registry diff \ my-spam-detector/1.0 \ my-spam-detector/2.0 # Shows: architecture changes, parameter delta, evaluation metric differences
Serve a model from registry directly (no --params needed):
docker exec matrixai matrixai serve \ --registry /data/registry \ --api-key secret123 \ --port 9000
The CLI ships a full toolchain for inspecting and maintaining model files. All commands accept --json for machine-readable output.
Lint — catch model errors before serving:
docker exec matrixai matrixai lint /data/my_model.mxai
# → OK my_model.mxai
docker exec matrixai matrixai lint /data/my_model.mxai --json
# → {"ok": true, "errors": [], "warnings": []}
# Use in CI to block bad models:
docker exec matrixai matrixai lint /data/my_model.mxai && echo "PASS" || echo "FAIL"Format — normalize and check formatting:
# Auto-format in place docker exec matrixai matrixai format /data/my_model.mxai # Check only (CI-safe, no writes) docker exec matrixai matrixai format /data/my_model.mxai --check # exits non-zero if file is not formatted
Graph — visualise model architecture:
# Print as Mermaid diagram docker exec matrixai matrixai graph /data/my_model.mxai --mermaid # JSON graph (nodes + edges) docker exec matrixai matrixai graph /data/my_model.mxai --json # Pipe Mermaid to a file for documentation docker exec matrixai matrixai graph /data/my_model.mxai --mermaid > model_graph.md
Diagnose — runtime vs compiled output check:
docker exec matrixai matrixai diagnose /data/my_model.mxai docker exec matrixai matrixai diagnose /data/my_model.mxai --json # Catches mismatches between the IR and what the runtime actually computes. # Useful after manual edits to a .mxai file.
Python — run lint as part of a model deployment pipeline:
import subprocess, json
def lint_model(container: str, model_path: str) -> dict:
result = subprocess.run(
["docker", "exec", container,
"matrixai", "lint", model_path, "--json"],
capture_output=True, text=True,
)
return json.loads(result.stdout)
report = lint_model("matrixai", "/data/my_model.mxai")
if not report["ok"]:
for err in report["errors"]:
print(f"ERROR: {err}")
raise RuntimeError("Model lint failed — blocking deployment")matrixai refine command uses the LLM to propose architecture or prompt changes based on an evaluation report.After training and evaluating a model, you can ask the LLM to improve it. Refinement takes an audit report (from matrixai evaluate) or anevaluation file and proposes changes.
Audit-driven refinement (most common):
# Basic: propose changes based on evaluation report docker exec matrixai matrixai refine \ "improve precision on the spam class" \ --audit /data/evaluation_report.json # Accept the proposal and write output files docker exec matrixai matrixai refine \ "improve precision on the spam class" \ --audit /data/evaluation_report.json \ --accept \ --output-mxai /data/my_model_v2.mxai \ --output-chain /data/chain.json # Add a hint to guide the refinement docker exec matrixai matrixai refine \ "improve accuracy" \ --audit /data/evaluation_report.json \ --hint "the model struggles with short emails under 50 words" \ --accept \ --output-mxai /data/my_model_v2.mxai
Metric-driven refinement:
docker exec matrixai matrixai refine \ "bring R² above 0.92 on the validation set" \ --evaluation /data/evaluation_report.json
Multi-iteration refinement loop:
# Iteration 1 docker exec matrixai matrixai refine "improve F1 score" \ --audit /data/eval_v1.json \ --iteration 1 --max-iterations 5 \ --accept \ --output-mxai /data/model_v2.mxai \ --output-chain /data/chain.json # Retrain v2, evaluate, then iteration 2 docker exec matrixai matrixai train supervised \ --model /data/model_v2.mxai --dataset /data/emails.csv docker exec matrixai matrixai evaluate \ --model /data/model_v2.mxai --params /data/params.json \ --dataset /data/test.csv > /data/eval_v2.json # Iteration 2 — chain file carries context from iteration 1 docker exec matrixai matrixai refine "continue improving F1" \ --audit /data/eval_v2.json \ --chain /data/chain.json \ --iteration 2 --max-iterations 5 \ --accept \ --output-mxai /data/model_v3.mxai \ --output-chain /data/chain_v2.json
Read prompt from stdin (useful in scripts):
echo "increase recall above 0.95 for class spam" | \
docker exec -i matrixai matrixai refine - \
--audit /data/evaluation_report.json \
--accept \
--output-mxai /data/model_refined.mxaimatrixai refine includes refinement_id, parent_hash, chain, and hints_applied. These fields form an audit trail linking each model version to the prompt that produced it.Grouped breakdown of the 42 functional sections covered by the test suite.
Download TEST_INDEX.mdCORE — 9,218 tests
STUDIO — 6,542 tests