How to Define Custom Model Scopes Using Minimatch in Pi Web
Pi Web uses minimatch glob patterns in lib/model-scope.ts to filter which language models are available to a session by matching against provider/modelId strings.
The agegr/pi-web repository implements a flexible model scoping system that lets you control exactly which AI models appear in your sessions. By leveraging the minimatch pattern matching library—the same engine powering the Pi SDK's --models CLI flag—you can define precise inclusion rules using wildcards, provider prefixes, and thinking-level suffixes.
What Are Model Scopes in Pi Web?
A model scope is a list of glob patterns that Pi Web evaluates to determine which models should be visible to a specific session. When you define a custom scope, the server-side resolver filters the full catalog of available models, ensuring only matching providers and model IDs are presented in the UI.
Scopes support complex matching against the canonical provider/modelId format. For example, the pattern anthropic/** matches every Anthropic model in the catalog, while openai/gpt-4*:medium matches GPT-4 variants with a specific thinking level.
How Model Scope Resolution Works
The resolution pipeline in lib/model-scope.ts processes scope definitions through three distinct phases before rendering the final model list.
Collecting Raw Scope Strings
Pi Web aggregates scope patterns from three sources in order of precedence:
- Global configuration – The
~/.pi/agent/models.jsonfile persists your default scope across sessions and is editable via the Models modal. - Session-specific overrides – The
POST /api/agent/newendpoint accepts amodelScopearray in the request body for one-time filtering. - Fallback defaults – If no patterns resolve to valid models, the system defaults to exposing all discovered models.
Resolving Glob Patterns
The resolveModelScopeWithDiagnostics() function delegates to the Pi SDK's resolver, which runs minimatch against each model's provider/modelId string. Pattern syntax includes:
- Simple matches –
"gpt-4"matches exact model IDs. - Provider scoping –
"anthropic/*"limits matches to a specific provider. - Wildcards –
*,?, and**operators match groups (e.g.,"google/**"matches all Google models). - Thinking levels – Suffixes like
:low,:medium, or:highpin the reasoning intensity for specific models.
Applying the Filtered List
After resolution, the scopedModels array is stored in the AgentSession wrapper by lib/rpc-manager.ts and transmitted to the frontend. The components/ModelsConfig.tsx component renders only these curated models, while malformed patterns trigger diagnostic warnings displayed in the Models modal.
Defining Custom Model Scopes
You can configure scopes interactively through the UI or programmatically via the API.
Via the Models Modal UI
The frontend provides a JSON editor for global scope configuration:
- Click the Models button in the bottom-left sidebar to open
components/ModelsConfig.tsx. - Locate the
enabledModelsarray and replace it with your minimatch patterns. - Save your changes – the UI sends a
PUTrequest toapp/api/models-config/route.ts, which writes to~/.pi/agent/models.jsonand triggers model rediscovery.
Programmatically via API
For session-specific scoping, include a modelScope array when creating an agent session:
{
"cwd": "/home/user/project",
"message": "Explain the code",
"modelScope": ["openai/gpt-4*", "anthropic/**", "google/**:low"]
}
The backend merges this array with the persisted global scope before calling the resolver in lib/model-scope.ts.
Minimatch Pattern Syntax Reference
Pi Web supports the full minimatch syntax for precise model selection:
- Single wildcards –
openai/gpt-4?matchesgpt-4oandgpt-4tbut notgpt-4-turbo. - Star wildcards –
openai/gpt-4*matches all GPT-4 variants including prefixes. - Globstars –
anthropic/**matches all Anthropic models regardless of depth. - Thinking modifiers – Append
:high,:medium, or:lowto set the reasoning level (e.g.,google/gemini-1.5-pro:high).
Practical Examples
Example 1: Configuring Scope via the UI
Update your global configuration to enable only high-performance models:
[
"openai/gpt-4*",
"anthropic/**",
"google/**:low"
]
After saving in the Models modal, app/api/models-config/route.ts persists this to ~/.pi/agent/models.json.
Example 2: API Request with Custom Scope
Create a session limited to specific OpenAI and Anthropic models:
curl -X POST https://your-pi-web.local/api/agent/new \
-H "Content-Type: application/json" \
-d '{
"cwd": "/home/user/project",
"message": "Summarize the repo",
"modelScope": ["openai/gpt-4*", "anthropic/**"]
}'
The server resolves these globs to concrete IDs like ["openai/gpt-4-1106-preview", "anthropic/claude-sonnet-3.5"] using resolveModelScopeWithDiagnostics().
Example 3: Pinning Thinking Levels
Require maximum reasoning for specific models while allowing others to use defaults:
{
"modelScope": ["google/gemini-1.5-pro:high", "openai/gpt-4o", "anthropic/claude-3-opus:medium"]
}
The resolver parses the :high and :medium suffixes and stores the thinking level alongside the resolved model ID.
Summary
- Model scopes in Pi Web are defined using minimatch glob patterns evaluated against
provider/modelIdstrings. - The resolution logic lives in
lib/model-scope.ts, specifically theresolveModelScopeWithDiagnostics()function. - Scopes can be set globally via
~/.pi/agent/models.json(edited throughcomponents/ModelsConfig.tsx) or per-session via themodelScopeparameter inPOST /api/agent/new. - Patterns support wildcards (
*,?,**) and thinking-level suffixes (:low,:medium,:high). - The
AgentSessionwrapper inlib/rpc-manager.tsstores the resolved list, whichlib/model-discovery.tsuses to filter the available catalog.
Frequently Asked Questions
What file handles the minimatch resolution for model scopes?
The lib/model-scope.ts file contains the core resolution logic. It exports resolveModelScopeWithDiagnostics(), which delegates to the Pi SDK's resolver to match glob patterns against the full model catalog.
Can I combine multiple patterns in a single scope?
Yes. The modelScope field accepts an array of strings, and the resolver treats this as a union of patterns. For example, ["openai/gpt-4*", "anthropic/claude-*"] includes any model matching either pattern.
How do thinking level suffixes work with glob patterns?
When you append a thinking level like :high or :low to a pattern (e.g., google/**:high), the resolver matches the base pattern against model IDs and then applies the specified reasoning level to all matches. The suffix is parsed after the glob match succeeds.
Where is the global models configuration stored?
Global scope settings are persisted in ~/.pi/agent/models.json on the server. The app/api/models-config/route.ts API route handles read and write operations for this file, while components/ModelsConfig.tsx provides the frontend editing interface.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →