Build on Molly — OpenAI-compatible, sovereign by default.
The Molly SDK speaks the OpenAI wire format. If you already have OpenAI code, point the base URL at Molly and you're running against your own sovereign multi-agent orchestrator — chat, stream, and train private specialists with no ML engineering required.
Overview
Every request routes through Molly's CEO orchestrator, which dispatches to LoRA specialists across a 4-tier stack — T0 on-device, T1 LAN, T2 self-hosted, T3 external API. Local is the default; higher tiers are policy-gated.
- OpenAI-compatible: reuse the official
openaiclients for Python & Node. - One model name: pass
"molly"— the orchestrator selects the specialist. - Plug-and-play training: submit a dataset, poll status, deploy a specialist.
- Provenance: responses are backed by Merkle-tree traceability.
Install
Install the native Molly client, or use the official OpenAI SDK pointed at Molly's base URL.
# Native Molly client (OpenAI-compatible)
pip install molly
# Or use the official OpenAI SDK
pip install openai
Authentication
Authenticate with a bearer API key from your workspace. Keys are prefixed mk-. Store it in an environment variable — never commit it.
| Field | Value |
|---|---|
| Base URL | https://app.iamolly.ai/api/molly/v1 |
| Auth header | Authorization: Bearer mk-... |
| Default model | molly (the orchestrator) |
MOLLY_API_KEY=mk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MOLLY_BASE_URL=https://app.iamolly.ai/api/molly/v1
Python quickstart
Use the official OpenAI SDK and set base_url to Molly. Call the orchestrator with the model name "molly".
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["MOLLY_API_KEY"],
base_url="https://app.iamolly.ai/api/molly/v1",
)
resp = client.chat.completions.create(
model="molly", # the orchestrator picks the specialist
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Summarize our Q3 support tickets."},
],
)
print(resp.choices[0].message.content)
Streaming
Set stream=True to receive tokens incrementally as server-sent events.
stream = client.chat.completions.create(
model="molly",
messages=[{"role": "user", "content": "Draft a release note."}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
Training jobs (plug-and-play)
Point Molly at your data — it trains, evaluates, and deploys a private LoRA specialist. Submit the dataset, poll status, then deploy. The native molly client exposes the training endpoints.
import os, time
from molly import Molly
client = Molly(api_key=os.environ["MOLLY_API_KEY"])
# 1. Upload a dataset (JSONL of chat examples)
dataset = client.datasets.upload(
file=open("support_tickets.jsonl", "rb"),
name="support-v1",
)
# 2. Submit a training job -> auto train + eval
job = client.training.create(
base="molly",
dataset=dataset.id,
specialist="support-agent",
)
# 3. Poll until the eval-gated job completes
while job.status not in ("succeeded", "failed"):
time.sleep(5)
job = client.training.retrieve(job.id)
print(job.status, job.eval_score)
# 4. Deploy the specialist into the orchestrator
if job.status == "succeeded":
client.specialists.deploy(job.specialist_id)
print("Deployed. Routable via model='molly'.")
Only distilled adapter deltas leave a node — never raw data. Every trained adapter is recorded in the Merkle-tree provenance log.
Node / TypeScript quickstart
Same approach in Node: use the official openai package and set baseURL.
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.MOLLY_API_KEY,
baseURL: "https://app.iamolly.ai/api/molly/v1",
});
const resp = await client.chat.completions.create({
model: "molly",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "Summarize our Q3 support tickets." },
],
});
console.log(resp.choices[0].message.content);
Streaming (Node)
const stream = await client.chat.completions.create({
model: "molly",
messages: [{ role: "user", content: "Draft a release note." }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
Error handling & rate limits
Molly returns standard HTTP status codes with an OpenAI-style error body. The default rate limit is 60 requests per minute; exceeding it returns 429. Back off and retry using the Retry-After header.
| Status | Meaning |
|---|---|
401 | Invalid or missing API key |
403 | Policy-gated tier not permitted for this key |
404 | Model or specialist not found |
429 | Rate limit exceeded (60 req/min) |
500 | Internal orchestration error |
import time
from openai import RateLimitError, APIError
def chat_with_retry(messages, retries=3):
for attempt in range(retries):
try:
return client.chat.completions.create(
model="molly", messages=messages,
)
except RateLimitError:
time.sleep(2 ** attempt) # exponential backoff
except APIError as e:
print(f"API error: {e}")
raise
raise RuntimeError("exhausted retries")
Local T0/T1 requests are not billed and count against a separate, higher limit. Rate limits apply per API key and can be raised on Team and Enterprise plans.