# How Pi Web Combines Model Configurations and Authentication Status: A Technical Deep Dive

> Learn how Pi Web combines model configurations and authentication status using a centralized models json file and runtime credential resolution. Explore the technical details in this deep dive.

- Repository: [Alex Yang/pi-web](https://github.com/agegr/pi-web)
- Tags: deep-dive
- Published: 2026-07-30

---

**Pi Web merges model settings and authentication credentials by storing both in a centralized [`models.json`](https://github.com/agegr/pi-web/blob/main/models.json) file and exposing unified API endpoints that resolve provider credentials at runtime.**

In the `agegr/pi-web` repository, the architecture unifies provider-specific model lists with their corresponding authentication state. This integration allows the UI to display a coherent view of which models are available and whether valid credentials exist to access them.

## Centralized Configuration in models.json

The system persists both model definitions and provider credentials in a single JSON file located at `~/.pi/agent/models.json`. This co-location ensures that authentication parameters travel with their associated model configurations.

### REST API for Configuration Management

The file [`app/api/models-config/route.ts`](https://github.com/agegr/pi-web/blob/main/app/api/models-config/route.ts) implements the HTTP interface for this storage. A `GET` request invokes `readModelsJson()` (lines 30-32) to return the raw configuration, while a `PUT` request uses `writeModelsJson()` (lines 34-38) to persist updates. After any write operation, the endpoint calls `invalidateModelsCache()` (line 38) to clear stale cached data.

## Runtime Authentication Resolution

When the application needs to verify or discover authentication details, it resolves credentials dynamically rather than relying solely on static file contents.

### Provider-Specific Discovery Auth

For model discovery operations, [`app/api/models-config/discover/route.ts`](https://github.com/agegr/pi-web/blob/main/app/api/models-config/discover/route.ts) imports `resolveModelDiscoveryAuth()` from [`lib/model-discovery-auth.ts`](https://github.com/agegr/pi-web/blob/main/lib/model-discovery-auth.ts) (line 53). This utility creates a temporary configuration containing only the target provider (lines 27-35), initializes a `ModelRuntime`, and extracts authentication via `modelRuntime.getAuth(model)`. The function returns an object containing `apiKey` and additional `headers` (lines 45-49), enabling secure API calls without exposing full configuration files.

### Global Auth Status Aggregation

To present authentication status across all providers, [`app/api/auth/all-providers/route.ts`](https://github.com/agegr/pi-web/blob/main/app/api/auth/all-providers/route.ts) enumerates known providers (lines 8-10) and queries `modelRuntime.getProviderAuthStatus(provider.id)` for each (line 26). The endpoint filters out OAuth-only providers and custom providers whose credentials originate from [`models.json`](https://github.com/agegr/pi-web/blob/main/models.json) (lines 25-28). Each result includes a `configured` boolean and a `source` field indicating `"env"` or `"config_file"`, allowing the UI to distinguish between environment variables and file-based credentials (lines 31-36).

## Merging Configuration with Auth Status in the UI

The frontend constructs a unified view by combining the static configuration from [`models.json`](https://github.com/agegr/pi-web/blob/main/models.json) with the runtime auth status. First, it fetches the stored configuration via `GET /api/models-config`, then retrieves live auth states via `GET /api/auth/all-providers`. The client merges these datasets to render provider cards that show both available models and authentication health.

```typescript
import { get } from "@/lib/agent-client";

// Fetch stored model configuration
const config = await get("/api/models-config");

// Fetch authentication status for each provider
const { providers } = await get("/api/auth/all-providers");

// Merge for UI rendering
const merged = providers.map(p => ({
  id: p.id,
  name: p.displayName,
  configured: p.configured,
  source: p.source,
  models: config.providers?.[p.id]?.models ?? [],
}));

```

## Cache Coordination and Data Consistency

To prevent stale data, the system implements an invalidation strategy in [`lib/models-cache.ts`](https://github.com/agegr/pi-web/blob/main/lib/models-cache.ts). Any mutation of [`models.json`](https://github.com/agegr/pi-web/blob/main/models.json)—whether through the PUT endpoint, login/logout flows, or API key updates—triggers `invalidateModelsCache()` (line 34). This clears the in-memory cache used by `loadModelsWithCache()` (lines 45-80), ensuring subsequent reads reload the updated file and reflect current authentication status.

## Practical Implementation Examples

### Updating Model Configuration

To add a custom provider with models and credentials, submit a PUT request to the configuration endpoint:

```typescript
await fetch("/api/models-config", {
  method: "PUT",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    providers: {
      mycustom: {
        apiKey: "sk-xxxx",
        models: [{ id: "my-model-1" }],
      },
    },
  }),
});

```

### Triggering Model Discovery with Auth Resolution

To discover available models for a specific provider while automatically resolving authentication:

```typescript
await fetch("/api/models-config/discover", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    provider: "openai",
    providerConfig: { apiKey: "sk-xxxx" },
  }),
});

```

## Summary

- Pi Web stores provider configurations and API keys together in `~/.pi/agent/models.json`, managed via [`app/api/models-config/route.ts`](https://github.com/agegr/pi-web/blob/main/app/api/models-config/route.ts).
- Runtime authentication resolution occurs through `resolveModelDiscoveryAuth()` in [`lib/model-discovery-auth.ts`](https://github.com/agegr/pi-web/blob/main/lib/model-discovery-auth.ts), which creates temporary runtimes to extract credentials.
- The [`app/api/auth/all-providers/route.ts`](https://github.com/agegr/pi-web/blob/main/app/api/auth/all-providers/route.ts) endpoint aggregates auth status across all providers, returning `configured` and `source` metadata.
- Cache consistency is maintained via `invalidateModelsCache()` in [`lib/models-cache.ts`](https://github.com/agegr/pi-web/blob/main/lib/models-cache.ts), triggered after any configuration mutation.
- The UI merges static configuration data with runtime auth status to present a unified provider health dashboard.

## Frequently Asked Questions

### How does Pi Web store authentication credentials?

Authentication credentials are stored alongside model definitions in the [`models.json`](https://github.com/agegr/pi-web/blob/main/models.json) file within the agent's data directory at `~/.pi/agent`. This file contains both the list of available models and per-provider API keys.

### What happens when I update the models configuration?

When you submit a PUT request to `/api/models-config`, the system writes to [`models.json`](https://github.com/agegr/pi-web/blob/main/models.json) and immediately calls `invalidateModelsCache()` (as implemented in [`lib/models-cache.ts`](https://github.com/agegr/pi-web/blob/main/lib/models-cache.ts) line 34). This clears the in-memory cache, ensuring that subsequent reads reflect the updated configuration and authentication status.

### How does the UI know if a provider is properly authenticated?

The frontend queries `GET /api/auth/all-providers`, which calls `modelRuntime.getProviderAuthStatus()` for each provider. The endpoint returns a `configured` boolean and a `source` field indicating whether credentials come from `"env"` variables or `"config_file"`, allowing the interface to display real-time authentication health.

### Can Pi Web discover models without manual configuration?

Yes. The `/api/models-config/discover` endpoint accepts a provider name and temporary configuration, then uses `resolveModelDiscoveryAuth()` to instantiate a runtime and extract authentication headers automatically. This enables model discovery without permanently storing credentials in [`models.json`](https://github.com/agegr/pi-web/blob/main/models.json).