Install and operate ParleML¶
Time: about 20 minutes to read · You need: ParleML running (Run ParleML), and access to the server's Docker commands. You'll end with: a server you can back up, upgrade, sign agents into and open to a team.
Run ParleML starts ParleML on your own machine. This page is for the person who runs it for others: what the container keeps, how to back it up and upgrade it, how to put it behind a proxy, and which settings matter.
In short
- Persist one volume,
/app/data_root. It holds everything ParleML keeps. - Keep agent logins in their own volumes (
/root/.codex,/root/.claude), or use API keys. - Behind a proxy, set
PARLEML_PUBLIC_URLandPARLEML_OAUTH_ISSUERto the public address. - For a team, turn on sign-in and set
PARLEML_MODE=prod. - No telemetry: only agents talk to their model provider, and
HF_HUB_OFFLINE=1makes the rest fully offline.
What runs in the container¶
One container serves everything on port 8000:
| Path | What it is |
|---|---|
/ |
The web application |
/api/ |
The API the application and your scripts call |
/mcp |
The MCP server for your own agents |
/docs |
The interactive API reference |
/help/ |
This documentation, and the ML4, MLI and agent guides |
The standard image is ghcr.io/parleml/parleml:0.8.0, about 7.7 GB once unpacked. It runs on CPU, includes
the Codex and Gemini CLI agents, and uses Codex by default.
The data volume¶
Everything ParleML keeps lives in one directory, the data root. In the image it is
/app/data_root. Mount a volume there, or everything is lost when the container is removed.
-v parleml-data:/app/data_root
To keep the data in a host directory instead, mount it and point PARLEML_DATA_ROOT at it:
-v /srv/parleml/data:/data -e PARLEML_DATA_ROOT=/data
What lives in the data root:
| Path | What it holds |
|---|---|
workspaces/<workspace id>/ |
Each workspace's datasets, experiments, models, knowledge bases and published documents |
catalog.db |
The index the lists and search read. Rebuild on Settings → Workspaces & data recreates it from the files. |
config/ |
What Settings edits: connections, profiles, skill packs, your skill edits, and vault.json, the encrypted secrets |
.secret_key |
The key that encrypts the vault and signs sign-in sessions |
agents/ |
Agent sessions: transcripts and the agents' work files |
mlflow/ |
MLflow runs, when there is no MLflow connection |
uploads/ |
Files staged from the browser |
users.json, api_tokens.json, user_prefs.json |
People, API tokens (hashed) and personal preferences |
audit_events.jsonl, oauth/ |
The audit log and connected agents |
Two things are not on the data volume:
- Agent logins. Each CLI keeps its sign-in in its own home directory. See Agents and sign-in.
- Model weights downloaded on first use. The image carries the default foundation-model weights. Others download the first time they are needed and stay in the container, so they download again after you recreate it. Settings → Diagnostics → Models on this server shows which are cached.
Back up and restore¶
Back up the whole data root, with ParleML stopped.
-
Stop ParleML:
docker stop parleml -
Copy the volume into an archive in the current directory:
docker run --rm -v parleml-data:/data -v "$PWD":/backup \ ghcr.io/parleml/parleml:0.8.0 tar czf /backup/parleml-data.tgz -C /data .docker run --rm -v parleml-data:/data -v "${PWD}:/backup" ` ghcr.io/parleml/parleml:0.8.0 tar czf /backup/parleml-data.tgz -C /data . -
Start ParleML again:
docker start parleml
To restore, stop ParleML and unpack the archive into an empty volume:
docker run --rm -v parleml-data:/data -v "$PWD":/backup \
ghcr.io/parleml/parleml:0.8.0 tar xzf /backup/parleml-data.tgz -C /data
Keep the vault and its key together
config/vault.json holds every connection's secret and the key that pseudonymises
identifier columns (card numbers, emails, phone numbers, IP addresses). A model that uses
it scores only with the key it was fitted with. .secret_key decrypts the vault. Back up
both together, and keep them out of shared backups. Losing either means refitting those
models and entering every connection's secret again.
Your version¶
Help (?) → About ParleML shows the release, the commit and date the image was built from, and the versions of ml4, mli, the agent runtime, the MCP server and the engines underneath. Copy versions puts them on the clipboard for a support question. The release is the image tag, and the image carries it as a label too:
docker inspect --format '{{ index .Config.Labels "org.opencontainers.image.version" }}' parleml
ParleML, ml4 and mli are released together under one version number.
Upgrade¶
- Back up the data volume.
-
Download the new image:
docker pull ghcr.io/parleml/parleml:<new-version><new-version>is the tag of the release you are moving to. -
Remove the old container. The data stays in the volume:
docker rm -f parleml -
Start the new image with the same
docker runoptions as before: the same volumes, ports and environment. - Open Help (?) → About ParleML and check the version.
Memory and CPU¶
Give the container at least 8 GB of memory. Give it more for large datasets, foundation models, text embeddings and explanations of large ensembles, which can take several GB each.
Docker Desktop sets the limit under Settings → Resources. On Linux, set it on the container, for example:
docker run -d --name parleml -p 8000:8000 --memory 16g --cpus 8 \
-v parleml-data:/app/data_root \
ghcr.io/parleml/parleml:0.8.0
ParleML queues heavy work rather than running it all at once. By default it runs one heavy job (an experiment fit, an explanation or a batch score) per four cores, and one explanation at a time. Settings → Diagnostics shows the job slots. Each fit uses every core it is given, so more jobs at once usually slows them all. To change the slots, see Background jobs.
No telemetry, and running offline¶
ParleML sends nothing home. It has no telemetry, no usage reporting and no update checks, and it switches off those of the tools it runs on:
- Libraries: MLflow and Hugging Face usage telemetry are off, and litellm uses its bundled price list instead of downloading one.
- Agent CLIs: Codex analytics, Gemini CLI usage statistics, and Claude Code telemetry and error reporting are off, and so are their update checks.
The only traffic that leaves the container is what you choose:
| Traffic | When | To keep it local |
|---|---|---|
| An agent's calls to its model provider | During agent sessions | Use a local model through Ollama or LM Studio |
| A model download | The first time you use a model the image doesn't include, such as a text-embedding model | Start the container with -e HF_HUB_OFFLINE=1 to forbid downloads |
| Your own connections | Databases, an MLflow server or an embeddings provider you add | Don't add them |
Everything else runs with no network at all: data, training, the default foundation models (TabICL and Chronos-2 are in the image), explanations, scoring and this documentation.
Agents and sign-in¶
The image includes Codex and Gemini CLI. Each agent needs an API key or a subscription login. Run ParleML shows both for one machine.
API keys go in the container's environment. On a team server, use keys that belong to the team: every session on the server uses them.
| Agent | Variables |
|---|---|
| Codex | OPENAI_API_KEY (or CODEX_API_KEY, CODEX_ACCESS_TOKEN) |
| Gemini CLI | GEMINI_API_KEY (or GOOGLE_API_KEY; or Vertex AI with GOOGLE_GENAI_USE_VERTEXAI=true and GOOGLE_CLOUD_PROJECT) |
| Claude Code (extended image) | ANTHROPIC_API_KEY (or ANTHROPIC_AUTH_TOKEN) |
| Cursor (extended image) | CURSOR_API_KEY |
A subscription login runs the agents on a ChatGPT, Claude or Google AI plan you already pay for, with no per-token bill. It is usually the cheapest choice for one person. The login is kept in the CLI's home directory inside the container. Mount a volume there so it survives an upgrade:
| Agent | Login volume | Sign in with |
|---|---|---|
| Codex | -v parleml-codex:/root/.codex |
docker exec -it parleml codex login --device-auth |
| Claude Code | -v parleml-claude:/root/.claude |
docker exec -it parleml claude, then /login |
| Gemini CLI | -v parleml-gemini:/root/.gemini |
docker exec -it parleml gemini, then Sign in with Google. An API key is simpler on a server. |
Then open Settings → Agents. Each agent shows Ready and, under Signed in with, where its credential comes from. The key itself is never shown.
PARLEML_AGENTS_HOST_ADAPTER sets the agent a profile uses when it names none: codex-cli
(the image's default), gemini-cli, claude-cli or cursor-cli.
Agent administrators can run programs on the server
An agent administrator can add a local (stdio) tool server, which the server starts as a
process. With sign-in on, every ParleML administrator is an agent administrator, so give
the role with care. In open mode, the anonymous user is an agent administrator only for
requests from inside the container, never through the published port — so on your own
machine Settings → Agents, Profiles, Skill packs and Connections stay closed. To open
them from your browser, start the container with PARLEML_OPEN_MODE_AGENT_ADMIN=true.
Anyone who can reach the port can then run programs on the server, so use it only where the
port is yours alone (the default -p 8000:8000 on a laptop; publish it as
-p 127.0.0.1:8000:8000 to keep it off the network), and turn on sign-in for a shared
server instead.
The extended image¶
Some options are not in the standard image, because of their licence, the origin of their data, or their size. Build them on top of it with one command; the recipe ships inside the image:
docker run --rm ghcr.io/parleml/parleml:0.8.0 cat /opt/parleml/Dockerfile.extended \
| docker build --build-arg WITH_CLAUDE=1 -t parleml-claude -
| Option | Build argument | What it gives you | Why it is not in the standard image |
|---|---|---|---|
| Claude Code | WITH_CLAUDE=1 (CLAUDE_VERSION pins a release) |
Agent sessions on Claude Code | Its licence grants no redistribution |
| Cursor | WITH_CURSOR=1 |
Agent sessions on Cursor (needs CURSOR_API_KEY) |
Its licence grants no redistribution |
| Name corpus | WITH_NAMES=1 |
Six features on name columns, such as a known first or last name and its country of origin | The corpus comes from a leaked data set; installing it is your call |
| fast.ai | WITH_FASTAI=1 |
The Neural net (fast.ai) model family | Size |
Add one --build-arg for each option you want; each defaults to 0. All four add about
1.5 GB. Then run your image in place of the standard one. For Claude Code as the default agent,
add -e PARLEML_AGENTS_HOST_ADAPTER=claude-cli.
Details: installing other Python packages
Install into the application's own environment, in a Dockerfile FROM the ParleML
image:
RUN pip --python /app/.venv/bin/python install <package>
A plain pip install goes to the system Python, which ParleML cannot see. Anything not in
the table above is untested.
The recipe builds on the image it came from. To read it before you pull the image, open parleml.com/extend/Dockerfile.extended, the same file for version 0.8.0. Your extended image is for your own use: don't push it to a public registry, because the licences of Claude Code and Cursor don't allow redistributing them.
GPU¶
The published image runs on CPU. A GPU build of the image carries the CUDA build of PyTorch (about 6 GB more, about 14 GB in all), which speeds up foundation models and text embeddings. Run a GPU build with access to the host's GPUs:
docker run -d --name parleml -p 8000:8000 --gpus all \
-v parleml-data:/app/data_root \
<gpu-image>
<gpu-image> is the name of your GPU build. Settings → Diagnostics → Hardware shows
whether ParleML sees the GPU.
IP geolocation (MaxMind)¶
Features that place an IP address on a map (country, city, network) need the MaxMind GeoLite2 databases. Their licence does not allow ParleML to ship them.
- Download
GeoLite2-City.mmdbandGeoLite2-ASN.mmdbfrom your MaxMind account into one directory on the host, for example/srv/parleml/maxmind. -
Mount that directory at
/data/maxmind:-v /srv/parleml/maxmind:/data/maxmind:ro -
Check it:
http://<your-server>:8000/api/describe/domainssays, for theipdomain, whether the data was found.
MAXMIND_DB_DIR already points at /data/maxmind. Without the files, IP columns still work,
without the geolocation features.
Behind a reverse proxy¶
Keep the container listening on port 8000, and publish it on any host port with -p. A TLS
proxy in front of it forwards to that port.
Then tell ParleML its public address:
| Variable | Set it to | Why |
|---|---|---|
PARLEML_PUBLIC_URL |
https://parleml.example.com |
The links agents give back open the web application here. Unset, ParleML uses each request's own address, which is wrong when the proxy rewrites the host. |
PARLEML_OAUTH_ISSUER |
The same address | Agent hosts such as claude.ai and ChatGPT discover ParleML's OAuth server from it. |
PARLEML_CORS_ORIGINS |
The same address | The browser origins allowed to call the API. |
claude.ai and ChatGPT call ParleML from their own servers, so they need it on public HTTPS.
PARLEML_AGENTS_SESSION_MCP_URL is where the agents inside the container reach ParleML. Its
default, http://127.0.0.1:8000/session-mcp/, is right as long as ParleML listens on port 8000
inside the container. If you change that port, set it (the trailing slash is required), and set
PARLEML_API_BASE to the same address and port.
Sign-on and production mode¶
A fresh container runs in open mode: anyone who can reach it can use it. For a team:
- Turn on sign-in with your identity provider. Set up single sign-on walks through it.
- Set
PARLEML_MODE=prod. The health check then hides the data root and library versions from callers who are not signed in, and sign-in cookies are sent over HTTPS only. - List the administrators in
PARLEML_ADMIN_EMAILS.
A complete team server, with the data in a host directory and MaxMind mounted:
docker run -d --name parleml -p 8000:8000 \
-e PARLEML_MODE=prod \
-v /srv/parleml/data:/data -e PARLEML_DATA_ROOT=/data \
-v /srv/parleml/maxmind:/data/maxmind:ro \
-e PARLEML_AUTH_REQUIRED=true \
-e PARLEML_OIDC_ISSUER=https://login.example.com \
-e PARLEML_OIDC_CLIENT_ID=<client-id> \
-e PARLEML_OIDC_CLIENT_SECRET=<client-secret> \
-e PARLEML_OIDC_REDIRECT_URI=https://parleml.example.com/api/auth/callback \
-e PARLEML_ADMIN_EMAILS=admin@example.com \
-e PARLEML_CORS_ORIGINS=https://parleml.example.com \
-e PARLEML_PUBLIC_URL=https://parleml.example.com \
-e PARLEML_OAUTH_ISSUER=https://parleml.example.com \
-e OPENAI_API_KEY=<team-openai-key> \
ghcr.io/parleml/parleml:0.8.0
<client-id> and <client-secret> come from your identity provider, and <team-openai-key>
is the team's key for Codex.
Details: the same server with Docker Compose
services:
parleml:
image: ghcr.io/parleml/parleml:0.8.0
ports: ["8000:8000"]
environment:
PARLEML_MODE: prod
PARLEML_AUTH_REQUIRED: "true"
PARLEML_OIDC_ISSUER: https://login.example.com
PARLEML_OIDC_CLIENT_ID: <client-id>
PARLEML_OIDC_CLIENT_SECRET: <client-secret>
PARLEML_OIDC_REDIRECT_URI: https://parleml.example.com/api/auth/callback
PARLEML_ADMIN_EMAILS: admin@example.com
PARLEML_CORS_ORIGINS: https://parleml.example.com
PARLEML_PUBLIC_URL: https://parleml.example.com
PARLEML_OAUTH_ISSUER: https://parleml.example.com
OPENAI_API_KEY: <team-openai-key>
volumes:
- parleml-data:/app/data_root
- parleml-codex:/root/.codex
- /srv/parleml/maxmind:/data/maxmind:ro
volumes:
parleml-data:
parleml-codex:
The most-used environment variables¶
| Variable | Default in the image | What it does |
|---|---|---|
PARLEML_DATA_ROOT |
/app/data_root |
Where everything is kept. Mount it. |
PARLEML_MODE |
dev |
Set prod on a team server. |
PARLEML_AUTH_REQUIRED |
false |
true makes every API and MCP call need a signed-in person or an API token. |
PARLEML_OIDC_ISSUER, …_CLIENT_ID, …_CLIENT_SECRET, …_REDIRECT_URI |
unset | Single sign-on with your identity provider. |
PARLEML_ADMIN_EMAILS |
empty | Comma-separated emails that become administrators when they sign in. |
PARLEML_OPEN_MODE_AGENT_ADMIN |
false |
Open mode only: lets the browser manage agent settings through the published port. Anyone who can reach the port can then run programs on the server. |
PARLEML_CORS_ORIGINS |
http://localhost:5173 |
Browser origins allowed to call the API. It cannot be * while sign-in is required. |
PARLEML_PUBLIC_URL |
each request's address | The public address of the web application. |
PARLEML_OAUTH_ISSUER |
each request's address | The public address agent hosts use for OAuth. |
PARLEML_AGENTS_HOST_ADAPTER |
codex-cli |
The default agent. |
PARLEML_AGENTS_SESSION_MCP_URL |
http://127.0.0.1:8000/session-mcp/ |
Where agents inside the container reach ParleML. |
PARLEML_MAX_UPLOAD_MB |
512 |
The largest single upload, in MiB. |
PARLEML_JOBS_HEAVY_CONCURRENCY |
0 (one per four cores) |
Heavy jobs running at once. |
MAXMIND_DB_DIR |
/data/maxmind |
Where the MaxMind databases are mounted. |
ML4_PSEUDONYMISATION_KEY |
the key in the vault | A pseudonymisation key of 32 characters or more. When set, it wins over the vault's. |
Configuration and settings keys lists every setting, and the backend configuration reference lists every agent setting.
Next¶
- Set up single sign-on: people sign in as themselves.
- Access, permissions and data: what people, agents and tokens can do.