# How to Manage Ollama Models (Download, Delete, List) in Project N.O.M.A.D.

> Learn to manage Ollama models (download, delete, list) in Project N.O.M.A.D. Discover how to interact with Ollama efficiently through REST endpoints and background job processing for seamless model management and progress strea...

- Repository: [Crosstalk Solutions/project-nomad](https://github.com/Crosstalk-Solutions/project-nomad)
- Tags: how-to-guide
- Published: 2026-03-16

---

**Project N.O.M.A.D. provides REST endpoints to list, download, and delete Ollama models via the `OllamaController` and `OllamaService`, with downloads processed as background jobs that stream progress to the UI.**

Project N.O.M.A.D. (Networked Operations Management and Deployment) is an open-source platform that wraps the Ollama container with a full-stack AdonisJS API. This guide explains how to manage Ollama models in Project N.O.M.A.D. using the built-in HTTP endpoints and underlying service architecture.

## Core Architecture

The model management system follows a layered architecture with clear separation between HTTP handling, business logic, and background processing.

### Controller Layer

The `OllamaController` at [`admin/app/controllers/ollama_controller.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/controllers/ollama_controller.ts) handles all HTTP requests under the `/api/ollama` route prefix defined in [`admin/start/routes.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/start/routes.ts). It exposes four primary actions:

- **`availableModels`** – Validates requests using `getAvailableModelsSchema` and delegates to `OllamaService.getAvailableModels()`
- **`installedModels`** – Returns locally installed models via `OllamaService.getModels()`
- **`dispatchModelDownload`** – Validates model names and enqueues `DownloadModelJob` through `OllamaService.dispatchModelDownload()`
- **`deleteModel`** – Validates input and calls `OllamaService.deleteModel()` to remove models

### Service Layer

The `OllamaService` in [`admin/app/services/ollama_service.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/services/ollama_service.ts) manages the Ollama client lifecycle and implements all model operations:

- **Client Initialization** – Lazily creates an `Ollama` client instance pointing to the Docker container URL
- **Remote Model Listing** – `getAvailableModels()` retrieves data from the Nomad API, caches results in [`storage/ollama-models-cache.json`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/storage/ollama-models-cache.json), and applies Fuse.js fuzzy search
- **Local Model Listing** – `getModels()` calls `ollama.list()` and filters out embedding models
- **Download Management** – `downloadModel()` streams pull progress while `dispatchModelDownload()` enqueues background jobs
- **Deletion** – `deleteModel()` forwards requests to `ollama.delete({ model })`

### Background Jobs and Broadcasting

Downloads run asynchronously via `DownloadModelJob` in [`admin/app/jobs/download_model_job.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/jobs/download_model_job.ts). The service broadcasts real-time progress via `broadcastDownloadProgress()` on the `BROADCAST_CHANNELS.OLLAMA_MODEL_DOWNLOAD` channel (defined in [`admin/constants/broadcast.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/constants/broadcast.ts)), enabling Server-Sent Events (SSE) updates in the UI.

## API Endpoints for Model Management

### List Available Remote Models

Query the Nomad registry for downloadable models with optional filtering and sorting.

```typescript
import axios from 'axios';

const response = await axios.get('/api/ollama/models', {
  params: {
    sort: 'pulls',        // Sort by popularity
    recommendedOnly: false,
    query: 'llama',       // Fuzzy search term
    limit: 15,
    force: false          // Bypass cache if true
  }
});

// Returns: { models: NomadOllamaModel[], hasMore: boolean }

```

The `OllamaService.getAvailableModels()` method checks [`storage/ollama-models-cache.json`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/storage/ollama-models-cache.json) first, refreshing every 24 hours unless `force=true`.

### List Installed Models

Retrieve models currently available in the local Ollama container.

```typescript
const { data } = await axios.get('/api/ollama/installed-models');
// Returns array of installed model objects (embeddings excluded)

```

This endpoint calls `OllamaService.getModels(includeEmbeddings = false)`, which wraps the native `ollama.list()` command.

### Download a Model

Initiate a background download by posting the model name.

```typescript
const { data } = await axios.post('/api/ollama/models', {
  model: 'qwen2.5:3b'
});

// Response: { message: "Download job dispatched for qwen2.5:3b" }

```

The `dispatchModelDownload()` method enqueues `DownloadModelJob`, which executes `downloadModel()` to stream the pull from `ollama.pull({ model, stream: true })`.

### Delete a Model

Remove a model from the local Ollama store.

```typescript
const { data } = await axios.delete('/api/ollama/models', {
  data: { model: 'qwen2.5:3b' }
});

// Response: { message: "Model deleted: qwen2.5:3b" }

```

This triggers `OllamaService.deleteModel()`, which calls the Ollama client's delete method.

## Implementation Details

### Caching Strategy

Remote model lists are cached in [`storage/ollama-models-cache.json`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/storage/ollama-models-cache.json) to minimize API calls. The cache automatically refreshes after 24 hours or immediately when the `force` parameter is set to `true` in the request.

### Fallback Data

If the remote Nomad API is unavailable, the system uses `FALLBACK_RECOMMENDED_OLLAMA_MODELS` from [`admin/constants/ollama.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/constants/ollama.ts) to ensure the UI remains functional.

### Type Safety

All model structures are defined in [`admin/types/ollama.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/types/ollama.ts), including `NomadOllamaModel`, `NomadOllamaModelTag`, and chat request/response interfaces. The controller uses Zod validators from [`admin/app/validators/ollama.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/validators/ollama.ts) for runtime request validation.

## Client-Side Integration Examples

### Monitoring Download Progress

Listen to SSE events for real-time download status:

```typescript
const source = new EventSource('/api/ollama/models');

source.addEventListener('message', (event) => {
  const { model, percent, completed, total } = JSON.parse(event.data);
  console.log(`Downloading ${model}: ${percent}% (${completed}/${total})`);
});

```

The `OllamaService.broadcastDownloadProgress()` method emits these events through the Transmit broadcasting layer.

### Complete Model Management Workflow

```typescript
class OllamaModelManager {
  async listAvailable() {
    return axios.get('/api/ollama/models');
  }
  
  async listInstalled() {
    return axios.get('/api/ollama/installed-models');
  }
  
  async download(name: string) {
    return axios.post('/api/ollama/models', { model: name });
  }
  
  async remove(name: string) {
    return axios.delete('/api/ollama/models', { data: { model: name } });
  }
}

```

## Summary

- **Listing** – Use `GET /api/ollama/models` for remote registry data (with caching) and `GET /api/ollama/installed-models` for local container models
- **Downloading** – `POST /api/ollama/models` enqueues background jobs via `DownloadModelJob`, streaming progress through `BROADCAST_CHANNELS.OLLAMA_MODEL_DOWNLOAD`
- **Deleting** – `DELETE /api/ollama/models` removes models via `OllamaService.deleteModel()`
- **Architecture** – Clean separation between `OllamaController` (HTTP), `OllamaService` (business logic), and background jobs for heavy operations

## Frequently Asked Questions

### How does Project N.O.M.A.D. handle large model downloads without blocking the API?

Downloads run asynchronously through `DownloadModelJob` in [`admin/app/jobs/download_model_job.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/app/jobs/download_model_job.ts). The controller immediately returns a success response after enqueueing the job, while the service streams download progress via Server-Sent Events on the `OLLAMA_MODEL_DOWNLOAD` broadcast channel.

### Where does Project N.O.M.A.D. store the list of available Ollama models?

Remote model metadata is cached in [`storage/ollama-models-cache.json`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/storage/ollama-models-cache.json) on the server. The `OllamaService.getAvailableModels()` method checks this file first and refreshes it every 24 hours or when the `force` parameter is specified.

### Can I filter or search through available models in the API?

Yes. The `GET /api/ollama/models` endpoint accepts a `query` parameter that triggers Fuse.js fuzzy searching in `OllamaService.getAvailableModels()`. You can also filter by `recommendedOnly` and sort results by `pulls` or other criteria.

### What happens if the remote Nomad API is unavailable when listing models?

The system falls back to `FALLBACK_RECOMMENDED_OLLAMA_MODELS` defined in [`admin/constants/ollama.ts`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/admin/constants/ollama.ts), ensuring the model selection UI remains functional even during network outages.