# How enabledModels Scoping Works with Minimatch Patterns in pi-web

> Discover how enabledModels scoping in pi-web utilizes minimatch patterns to filter AI models by provider/modelId. Learn how this ensures consistent scoping logic across web and TUI interfaces.

- Repository: [Alex Yang/pi-web](https://github.com/agegr/pi-web)
- Tags: internals
- Published: 2026-08-15

---

**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`](https://github.com/agegr/pi-web/blob/main/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:

```json
{
  "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 `enabledModels` match against `provider/modelId` strings 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.ts`](https://github.com/agegr/pi-web/blob/main/lib/model-scope.ts) wraps the SDK's `resolveModelScopeWithDiagnostics()` to ensure `pi-web` and the TUI interpret patterns identically.
- [`lib/rpc-manager.ts`](https://github.com/agegr/pi-web/blob/main/lib/rpc-manager.ts) resolves the scope atomically during `startRpcSession()` before creating the `AgentSession`.
- The system falls back to all models if patterns resolve to nothing, logging warnings to `modelScopeWarnings` for 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`](https://github.com/agegr/pi-web/blob/main/lib/model-scope.ts), which imports and wraps the Pi SDK's `resolveModelScopeWithDiagnostics()`. Session initialization in [`lib/rpc-manager.ts`](https://github.com/agegr/pi-web/blob/main/lib/rpc-manager.ts) consumes this utility, while [`app/api/models/route.ts`](https://github.com/agegr/pi-web/blob/main/app/api/models/route.ts) reuses it to serve the filtered model list to the frontend.