Files
ThothII/docs/general/pi-configuration.md
T

9.5 KiB

Local Pi model configuration

Pi orchestrates the NL-to-SQL workflow and resolves built-in models and OpenAI-compatible providers declared in the local catalog. ThothII applies a stricter rule than Pi: code in harness/.pi/extensions/ cannot register a provider or custom model. Endpoints, protocols, compatibility settings, and model identifiers belong exclusively in the local files deploy/pi/models.json and deploy/pi/settings.json.

ThothII operator note: ThothII runs Pi only in Docker Compose. Paths under ~/.pi/agent/ in this document describe Pi's container-side behavior. Operators edit deploy/pi/models.json and deploy/pi/settings.json in the ThothII project root and use the protected host credential file selected by PI_AUTH_FILE; they do not edit files inside the running container.

Credentials in the backend container

In production, configure one generic source: the THT_SECRETS_FILE bundle with the THT_MODEL_API_KEY entry, which is the default for the unified distribution, or THT_MODEL_API_KEY_FILE as an absolute secret-file path. Do not put the key value in .env. For each process, PiProcessManager rereads and validates the source, normalizes the selected provider, and passes only the appropriate native variable to the Pi child (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, ZAI_API_KEY, and so on). It removes the generic path, keys for unselected providers, and the old PI_PROVIDER_API_KEY from the child environment. For a custom provider, the backend derives the variable name from the declarative apiKey field in models.json; a literal value means the catalog is self-contained. Provider-name exceptions are not compiled into the code. A missing or insecure secret fails before spawn with a sanitized error.

The generic source supports only single-key providers: ant-ling, anthropic, cerebras, deepseek, fireworks, github-copilot, google (including the gemini alias), google-vertex in API-key mode, groq, huggingface, kimi-coding, minimax, minimax-cn, mistral, moonshotai, moonshotai-cn, nvidia, openai, opencode, opencode-go, openrouter, together, vercel-ai-gateway, xai, the four xiaomi* providers, zai, and zai-coding-cn.

The composite providers amazon-bedrock, azure-openai-responses, cloudflare-workers-ai, and cloudflare-ai-gateway cannot be represented by one file. Selection fails before spawn, including when models are listed. AWS, Azure, and Cloudflare environment credentials are still removed. A future provider-specific configuration will be needed to support these bundles unambiguously.

Model sources

1. Built-in (compiled into Pi)

Pi ships with a list of known models (models.generated.js in the @earendil-works/pi-ai package): Anthropic, OpenAI, Google, and third-party providers with well-known public APIs such as DeepSeek. These require no configuration beyond credentials, provided through an environment variable or pi auth.

deepseek/deepseek-v4-pro is one of these models. It is included in Pi because api.deepseek.com is a documented public API, not an internal endpoint.

2. User-level models.json (~/.pi/agent/models.json)

For an OpenAI-compatible endpoint that is not built in but needs no special transport logic, declare it with its baseUrl, apiKey, and model list. This file exists only at user level; there is no project-level equivalent, and ./.pi/models.json is not read.

In ThothII-managed installations, the file must be entirely declarative. ThothII recursively rejects any JSON value that starts with !, including values inside headers, models, modelOverrides, compat, arrays, or fields it does not yet know. Pi 0.80.3 would treat that prefix as a shell command when making a request, so managed model catalogs do not allow it. The returned error is fixed and contains no command, path, or secret.

For secrets, use an environment reference such as "$ZAI_API_KEY" or "${ZAI_API_KEY}". The backend can populate the native variable for the selected provider by reading THT_MODEL_API_KEY_FILE, or from the THT_SECRETS_FILE bundle (THT_MODEL_API_KEY). Credentials can also come from the protected file mounted through PI_AUTH_FILE, with apiKey omitted from models.json. There is no direct secret-file reference syntax in models.json. With THT_MODEL_* sources, ThothII reads the file and turns it into the Pi child's environment variable; PI_AUTH_FILE is mounted instead as a protected Pi credential store. For a literal leading exclamation mark, Pi's declarative syntax is $!, not !.

Real example in use on this machine: GLM (provider zai):

{
  "providers": {
    "zai": {
      "baseUrl": "https://api.z.ai/api/coding/paas/v4",
      "api": "openai-completions",
      "apiKey": "$ZAI_API_KEY",
      "models": [
        {
          "id": "glm-5.2",
          "name": "GLM-5.2",
          "reasoning": true,
          "contextWindow": 200000,
          "maxTokens": 131072
        }
      ]
    }
  }
}

Because it is user-level, GLM is visible to every project.

Extension providers: not allowed in ThothII

Pi technically supports providers registered by JavaScript extensions, but ThothII does not use that capability. Project extensions are reserved for the workflow and gates; they must not contain registerProvider(...). An endpoint that cannot be described by the OpenAI-compatible catalog is not supported by this installation until the declarative contract is extended generically.

Summary table (current machine state)

Model Level Why Visibility
deepseek/deepseek-v4-pro Built-in Pi Known public API, already in the build All projects
zai/glm-5.3 deploy/pi/models.json Custom OpenAI-compatible endpoint ThothII installation
local-qwen/qwen3.6-35b-a3b deploy/pi/models.json Locally configured OpenAI-compatible endpoint ThothII installation

Choosing the right level for a new model

  1. Is the endpoint a public API already known to Pi? Enable the exact identifier in deploy/pi/settings.json.
  2. Is it OpenAI-compatible but not built in? Declare it in deploy/pi/models.json, then enable it in deploy/pi/settings.json.
  3. Does it require provider-specific transport code? Do not add a provider-specific extension. The provider is unsupported until a generic declarative capability exists.

User versus project scope: general summary

In addition to models, Pi loads other resources from two parallel trees: ~/.pi/agent/ (user) and <cwd>/.pi/ (project, resolved from the directory where pi is launched).

File/Directory Livello utente Livello progetto Auto-discovery Precedenza
models.json ~/.pi/agent/models.json not supported no user only
settings.json ~/.pi/agent/settings.json ./.pi/settings.json no project overrides user
extensions/ ~/.pi/agent/extensions/ ./.pi/extensions/ yes (.ts/.js) merged (project + user)
prompts/ ~/.pi/agent/prompts/ ./.pi/prompts/ yes (.md) merged
themes/ ~/.pi/agent/themes/ ./.pi/themes/ yes (.json) project preferred
skills/ ~/.pi/agent/skills/ ./.pi/skills/ yes (.md) merged

Real example: ThothII

harness/.pi/
├── extensions/
│   ├── tht-gate.js               # human-in-the-loop gate
│   └── gate/
│       ├── core/                 # shared gate enforcement and utilities
│       ├── disambiguation/       # F1/F3 policy
│       └── memory/               # F2/F8 policy
├── settings.json                 # optional override of user settings
└── themes/
    └── thothii-mono.json         # project theme

Behavior relative to cwd

The directory from which you launch pi determines which workflow extensions are found, but not which models ThothII makes available. The catalog is mounted in the container's Pi agent directory.

# From harness/: load the project gate and mounted local catalog
cd /path/to/ThothII/harness
pi --model local-qwen/qwen3.6-35b-a3b "..."

The ThothII backend always launches Pi with cwd: harnessDir for the workflow. Model availability continues to depend only on models.json, settings.json, and local credentials.


Auto-discovery trap: .mjs is ignored

Pi's extension auto-discovery pattern is /\.(ts|js)$/; it does not include .mjs.

.pi/extensions/
├── my-extension.js      ✅ auto-loaded
├── my-extension.ts      ✅ auto-loaded
├── my-extension.mjs     ❌ silently ignored (does not match the pattern)
└── shared-module.mjs    ✅ suitable for helper modules (deliberately not loaded as an extension)

If an extension imports a shared module, use .mjs so Pi does not treat it as an extension on its own.


Verifica

List models

pi --list-models

This shows built-in models and models declared in models.json.

Check the catalog used by the application

cd harness   # or the project's relevant cwd
pi --mode rpc
# poi: {"type": "get_available_models", "id": "1"}

The RPC response must include only built-in models or models declared in the local catalog.


Troubleshooting

Problem Cause Solution
Model "X/Y" not found Provider/model missing from models.json or identifier missing from enabledModels Fix the two local files and reload Pi
Project settings not applied Project settings.json has a syntax error, or pi is launched from the wrong cwd Validate the JSON and check the cwd