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

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 handles all HTTP requests under the /api/ollama route prefix defined in 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 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 ListinggetAvailableModels() retrieves data from the Nomad API, caches results in storage/ollama-models-cache.json, and applies Fuse.js fuzzy search
  • Local Model ListinggetModels() calls ollama.list() and filters out embedding models
  • Download ManagementdownloadModel() streams pull progress while dispatchModelDownload() enqueues background jobs
  • DeletiondeleteModel() forwards requests to ollama.delete({ model })

Background Jobs and Broadcasting

Downloads run asynchronously via DownloadModelJob in 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), 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.

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 first, refreshing every 24 hours unless force=true.

List Installed Models

Retrieve models currently available in the local Ollama container.

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.

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.

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 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 to ensure the UI remains functional.

Type Safety

All model structures are defined in admin/types/ollama.ts, including NomadOllamaModel, NomadOllamaModelTag, and chat request/response interfaces. The controller uses Zod validators from 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:

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

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
  • DownloadingPOST /api/ollama/models enqueues background jobs via DownloadModelJob, streaming progress through BROADCAST_CHANNELS.OLLAMA_MODEL_DOWNLOAD
  • DeletingDELETE /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. 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 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, ensuring the model selection UI remains functional even during network outages.

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 →