Skip to content

Configuration

Configuration comes from four places. Knowing which one wins saves a lot of confusion.

The four layers

LayerSet fromApplies to
SessionThe pills under the composerOne session
PortalSettings → GeneralNew sessions
EnvironmentCompose / .envThe deployment
pi~/.pi/agent/settings.jsonpi itself, everywhere

For model, effort and provider, they resolve in that order — first non-empty wins, with a last-resort constant behind pi:

session → portal override → environment → pi settings.json → fallback

Everything past the session layer is a default. A session that has made its own choice keeps it, and changing a default never rewrites a running session.

Empty means inherit

PI_PROVIDER, PI_MODEL and PI_THINKING_LEVEL are overrides, and they are empty in the compose file on purpose. Give them a value and pi's own settings.json can never be reached. The same is true in Settings → General: an empty field inherits, and clearing one hands the setting back.

Environment

VariableDefaultMeaning
PORTAL_PASSWORDRequired. The single login password.
PORTAL_SECRETrandomSigns the cookie. Set it to survive restarts.
PORT4100Listen port.
DATA_DIR/dataWhere portal.db lives.
SESSION_DIR/data/sessionsPer-session working areas.
WORKSPACE_ROOT/workspacesDirectories sessions can be created against.
CHANNELS_DIR/data/channelsInstalled channel packages.
AGENT_HOME/data/agent-homeThe agent session's directory.
HOME/data/homepi's home — its settings and packages.
EXECUTORhosthost or container.
PI_IMAGEpithagoras-runner:latestImage for the container executor.
TASK_MEMORY_MB2048Container executor memory ceiling.
TASK_CPUS2Container executor CPU ceiling.
TASK_PIDS_LIMIT512Container executor process ceiling.
PI_PROVIDEROverride for pi's defaultProvider.
PI_MODELOverride for pi's defaultModel.
PI_THINKING_LEVELOverride for pi's defaultThinkingLevel.

Provider credentials — OPENROUTER_API_KEY, ANTHROPIC_API_KEY and anything else pi reads — pass through untouched.

HOME on the data volume is load-bearing. Point it back at the container filesystem and every image rebuild silently wipes the pi packages you installed.

pi's settings.json

Lives at $HOME/.pi/agent/settings.json/data/home/.pi/agent/settings.json in the container. Editable from Settings → Advanced, which validates it as JSON before writing; a broken file stops every future session from starting.

json
{
  "defaultProvider": "llama-server=http://192.168.1.101:8080",
  "defaultModel": "qwen36-35b-a3b-mtp",
  "defaultThinkingLevel": "high",
  "packages": ["npm:pi-llama-cpp"],
  "llamaServerUrl": "http://192.168.1.101:8080",
  "compaction": { "enabled": true }
}

Extension settings live here too, alongside pi's own. That is why the portal writes single keys rather than replacing the file: a wholesale overwrite would take the packages list with it.

Portal settings

Stored in the settings table, edited in Settings → General. Saving an empty value deletes the row rather than storing an empty string, which is what makes "inherit" reachable again after you have set something.

The GET /api/settings response separates the three so a client can tell them apart:

json
{
  "settings": { "provider": "llama-server=…", "model": "qwen36-35b-a3b-mtp" },
  "stored":   {},
  "defaults": { "provider": "llama-server=…", "model": "qwen36-35b-a3b-mtp" }
}

stored empty and settings matching defaults means everything is inherited — nothing is pinned.

Give it a task, close the browser, come back later.