How FreeLLMAPI Catalog Sync Updates Model Information: A Technical Deep Dive

FreeLLMAPI automatically synchronizes its local SQLite model database with a cryptographically signed remote catalog every 12 hours, updating model metadata and availability flags while preserving user overrides and custom configurations.

The tashfeenahmed/freellmapi repository maintains an up-to-date registry of AI models through a sophisticated catalog synchronization system. This process ensures that the routing layer always has accurate information about which models can serve incoming requests, while maintaining security through cryptographic verification. Understanding how the FreeLLMAPI catalog sync updates model information is essential for operators managing self-hosted instances or integrating with premium model providers.

The Three-Stage Catalog Sync Architecture

The update flow operates as a pipeline with distinct responsibilities: remote fetching, local persistence, and runtime availability calculation.

Fetching and Verifying the Remote Catalog

The synchronization initiates in server/src/services/catalog-sync.ts through the startCatalogSync function. This scheduler registers two execution paths: an initial boot-delay run and a repeated interval governed by SYNC_INTERVAL_MS = 12h.

The syncCatalog() function constructs a request to the /v1/latest endpoint, appending a Bearer token when a premium license key is configured. The request includes a timeout defined by FETCH_TIMEOUT_MS. Upon receiving the response, the system validates the x-catalog-signature header by verifying the raw response body against a hard-coded Ed25519 public key retrieved via catalogPublicKey(). If cryptographic verification fails, the entire catalog payload is discarded to prevent tampering.

Applying Updates to the Local Database

Once verified, the applyCatalog() function processes the incoming CatalogModel entries. This stage differentiates between chat models and media generation models by inspecting the modality field against MEDIA_MODALITIES, routing entries to either the models or media_models SQLite tables.

For each entry, the system performs an upsert operation:

  • Updates existing rows while preserving the local enabled flag unless the catalog explicitly disables the model
  • Inserts new rows for models not yet present in the local database
  • Skips entries where platform === 'custom' or where local tombstone overrides exist

After processing all catalog entries, the function performs garbage collection by deleting models removed from the remote catalog, clearing tombstoned rows, and refreshing user-provided overrides through applyAllModelOverrides.

Deriving Runtime Availability for Routing

The final stage occurs in server/src/services/model-listing.ts within the buildModelListing() function. Rather than directly querying the enabled column, the system computes a dynamic available flag using a SQL expression that joins against the api_keys table:

(CASE WHEN m.enabled = 1 AND EXISTS (
     SELECT 1 FROM api_keys k
     WHERE k.platform = m.platform
       AND k.enabled = 1
       AND (m.key_id IS NULL OR k.id = m.key_id)
) THEN 1 ELSE 0 END)

This expression evaluates to 1 only when the model is catalog-enabled and an active API key exists for its platform. The resulting availability flag drives the GET /v1/models endpoint exposed by server/src/services/router.ts and determines the "auto" context-window ceiling calculations.

Implementation Details and Code Examples

Initializing Background Synchronization

To start the automatic catalog refresh at server startup:

import { startCatalogSync } from './services/catalog-sync.js';
import { Scheduler } from './lib/scheduler.js';

const scheduler = new Scheduler();
startCatalogSync(scheduler);

Triggering Manual Catalog Updates

For on-demand synchronization, such as after adding a premium license key:

import { syncCatalog } from './services/catalog-sync.js';

async function refreshCatalog() {
  const result = await syncCatalog(true); // force = true bypasses the `since` short-circuit
  console.log('Catalog refresh result:', result);
}

Querying Available Models

The routing layer consumes the catalog state through the listing service:

import { buildModelListing } from './services/model-listing.js';

function listModels() {
  const { models, autoContextWindow } = buildModelListing();
  console.log('Available models:', models);
  console.log('Auto context window:', autoContextWindow);
}

Database State and Override Management

The server/src/services/model-state.ts module maintains the integrity between catalog-managed and user-configured settings. Custom models added directly by users remain untouched during sync operations, while tombstone markers allow administrators to suppress specific catalog models permanently. The enabled column serves as the bridge between the catalog sync process (which writes it) and the model listing logic (which reads it alongside API key validity).

Summary

  • FreeLLMAPI catalog sync runs automatically every 12 hours via startCatalogSync in catalog-sync.ts, with optional on-demand execution through syncCatalog(true).
  • Cryptographic verification using Ed25519 signatures ensures the remote catalog at /v1/latest has not been tampered with before local application.
  • Dual-table architecture separates chat models (models table) from media models (media_models table) based on the modality field.
  • Availability calculation combines the catalog's enabled flag with active API key presence, computed dynamically in buildModelListing() within model-listing.ts.
  • User overrides and custom platform models are preserved during sync operations, allowing local configuration to persist across catalog updates.

Frequently Asked Questions

How often does FreeLLMAPI synchronize the model catalog?

The system schedules automatic synchronization every 12 hours using the SYNC_INTERVAL_MS constant, with an initial delay at server startup. Administrators can trigger additional updates manually by calling syncCatalog(true) to bypass the incremental since parameter check.

What happens if the remote catalog signature verification fails?

If the x-catalog-signature header cannot be verified against the hard-coded Ed25519 public key in catalogPublicKey(), the entire catalog payload is rejected. The local database retains its previous state, ensuring that corrupted or malicious catalog data never affects the available model list.

Can I prevent specific catalog models from appearing in my instance?

Yes. The system respects tombstone markers and custom platform designations. Models marked as platform === 'custom' or those with local override entries in the database are excluded from catalog sync updates, allowing administrators to suppress unwanted models permanently.

Why are some models disabled despite being present in the latest catalog?

A model appears unavailable when either the catalog sets enabled = 0 or when no active API key exists for the model's platform. The SQL availability expression in model-listing.ts requires both conditions—catalog enablement and valid API key presence—to mark a model as available for routing.

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 →