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:

  1. Global configuration – The ~/.pi/agent/models.json file persists your default scope across sessions and is editable via the Models modal.
  2. Session-specific overrides – The POST /api/agent/new endpoint accepts a modelScope array in the request body for one-time filtering.
  3. 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 :high pin 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:

  1. Click the Models button in the bottom-left sidebar to open components/ModelsConfig.tsx.
  2. Locate the enabledModels array and replace it with your minimatch patterns.
  3. Save your changes – the UI sends a PUT request to app/api/models-config/route.ts, which writes to ~/.pi/agent/models.json and 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? matches gpt-4o and gpt-4t but not gpt-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 :low to 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/modelId strings.
  • The resolution logic lives in lib/model-scope.ts, specifically the resolveModelScopeWithDiagnostics() function.
  • Scopes can be set globally via ~/.pi/agent/models.json (edited through components/ModelsConfig.tsx) or per-session via the modelScope parameter in POST /api/agent/new.
  • Patterns support wildcards (*, ?, **) and thinking-level suffixes (:low, :medium, :high).
  • The AgentSession wrapper in lib/rpc-manager.ts stores the resolved list, which lib/model-discovery.ts uses 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →