How enabledModels Scoping Works with Minimatch Patterns in pi-web
The enabledModels setting in pi-web uses minimatch glob patterns to filter available AI models by matching against provider/modelId strings, delegating resolution to the Pi SDK's resolveModelScopeWithDiagnostics() to ensure the web UI and TUI share identical scoping logic.
The pi-web repository provides a web interface for the Pi AI agent framework, allowing users to restrict which models appear in the UI through the enabledModels configuration. This setting leverages minimatch glob syntax combined with fuzzy matching and optional thinking-level modifiers to control model visibility atomically across sessions.
Minimatch Pattern Syntax in enabledModels
The enabledModels array accepts patterns that follow the Pi CLI's --models syntax, supporting three distinct matching strategies.
Glob Patterns Against Provider/Model Paths
Minimatch globs target the full provider/modelId identifier. For example, anthropic/* matches all models from the Anthropic provider, while openai/gpt-3.* captures specific model families using wildcard characters.
Fuzzy Matching for Bare Identifiers
When a pattern contains no glob characters and no provider prefix, the resolver treats it as a fuzzy match against bare modelId values. This allows entries like claude-sonnet-4 to match models without specifying the exact provider path.
Thinking Level Pin Suffixes
Patterns may append a colon-separated thinking level—:high, :medium, or :low—to set the default reasoning intensity for matched models. For instance, anthropic/*:high applies high thinking to all Anthropic models while keeping them in the allowed set.
Resolution Flow in lib/model-scope.ts and lib/rpc-manager.ts
Rather than comparing patterns as literal strings, pi-web delegates resolution to the Pi SDK to maintain consistency with the TUI.
When startRpcSession() initializes a new agent session, it invokes resolveModelScopeWithDiagnostics() from lib/model-scope.ts. This function expands the enabledModels patterns into a concrete scopedModels array. If no patterns match any available models, the resolver falls back to exposing all models and populates modelScopeWarnings to alert the user in the interface.
The resolution happens atomically: the initial model selection, thinking pin configuration, and the finalized scopedModels array pass together into the AgentSession constructor.
API Endpoint and UI Consumption
The GET /api/models endpoint reuses the same resolution helper to populate the model selector interface. It returns the filtered model list alongside thinkingLevelPins and any modelScopeWarnings generated during pattern resolution.
This design ensures that the settings modal, chat interface, and session initialization all reference the same canonical list of visible models derived from the minimatch patterns.
Configuration Example
Define your model restrictions in ~/.pi/agent/settings.json using valid minimatch syntax:
{
"enabledModels": [
"anthropic/*:high",
"openai/gpt-4",
"gemini-pro",
"cohere/*:medium"
]
}
This configuration exposes all Anthropic models with high thinking enabled, the specific GPT-4 model from OpenAI, any model fuzzy-matching "gemini-pro", and all Cohere models defaulting to medium thinking levels.
Summary
- Minimatch globs in
enabledModelsmatch againstprovider/modelIdstrings to filter the available model list. - Fuzzy matching applies to bare model IDs without providers or glob characters.
- Thinking level suffixes (
:high,:medium,:low) pin default reasoning levels for matched models. lib/model-scope.tswraps the SDK'sresolveModelScopeWithDiagnostics()to ensurepi-weband the TUI interpret patterns identically.lib/rpc-manager.tsresolves the scope atomically duringstartRpcSession()before creating theAgentSession.- The system falls back to all models if patterns resolve to nothing, logging warnings to
modelScopeWarningsfor display in the UI.
Frequently Asked Questions
What happens if my minimatch pattern matches no models?
If the patterns in enabledModels resolve to an empty set, the resolveModelScopeWithDiagnostics() function falls back to exposing all available models and generates a warning in modelScopeWarnings that appears in the UI, ensuring users are not accidentally left with zero selectable models.
Can I mix glob patterns and exact model IDs in enabledModels?
Yes, the enabledModels array accepts a heterogeneous mix of minimatch globs, exact provider/modelId strings, and bare model IDs for fuzzy matching. The resolver processes each pattern sequentially and unions the results into the final scopedModels list.
How does pi-web handle thinking level pins in model patterns?
When a pattern includes a suffix like :high, the resolver strips this modifier before matching the model identifier, then associates the specified thinking level with all models that match that pattern. These pins are passed atomically with the scopedModels to the AgentSession and exposed via the thinkingLevelPins data structure in the API.
Where is the model scope resolution logic implemented?
The core logic resides in lib/model-scope.ts, which imports and wraps the Pi SDK's resolveModelScopeWithDiagnostics(). Session initialization in lib/rpc-manager.ts consumes this utility, while app/api/models/route.ts reuses it to serve the filtered model list to the frontend.
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 →