agents-inc/skills/src/skills/ai-infrastructure-ollama/SKILL.md
ai-infrastructure-ollama
Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint
- Source repository stars
- 21
- Declared platforms
- 0
- Static risk flags
- 1
- Last source update
- 2026-08-09
- Source checked
- 2026-08-25
Decision brief
What it does: where it fits
Quick Guide: Use the ollama npm package to run LLMs locally. Use ollama.chat() for conversations and ollama.generate() for single prompts. Enable streaming with stream: true and iterate with for await. Use format with a JSON schema (via zodToJsonSchema) for structured outputs. U…
Not for
- Tasks that require unconfirmed production actions or broad system permissions.
- Environments where the pinned source and install steps cannot be inspected.
Compatibility matrix
Platform support, with evidence labels
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
Inspect first. Install second.
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/agents-inc/skills --skill "src/skills/ai-infrastructure-ollama"Inspect the Agent Skill "ai-infrastructure-ollama" from https://github.com/agents-inc/skills/blob/81d43a51211aca12c85dcc16085fa99014ec548e/src/skills/ai-infrastructure-ollama/SKILL.md at commit 81d43a51211aca12c85dcc16085fa99014ec548e. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
What the source asks the agent to do
- 01
Pattern 1: Client Setup
The default import is a pre-configured singleton pointing to http://127.0.0.1:11434.
The default import is a pre-configured singleton pointing to http://127.0.0.1:11434.Why good: Minimal setup, default client requires zero configuration, custom client for remote serversWhy bad: Creates a new client instance per request, no reuse, host scattered across codebase - 02
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)
Running LLMs locally for development, testing, or privacy-sensitive workloadsBuilding chat applications with local models (Llama, Mistral, Qwen, Gemma, etc.)Extracting structured data from text or images using local models with JSON schemas - 03
Examples Index
Core: Setup, Chat & Generate -- Client init, chat, generate, streaming, error handling
Core: Setup, Chat & Generate -- Client init, chat, generate, streaming, error handlingTool Calling -- Tool definitions, single/parallel calls, multi-turn agent loopsStructured Output -- JSON schema via Zod, vision extraction - 04
Philosophy
The Ollama JavaScript library is a thin client over Ollama's local REST API (default http://127.0.0.1:11434). It provides direct access to locally-running open-source LLMs with zero cloud dependencies.
Local-first -- Models run on your hardware. No API keys required for local use, complete data privacy, no per-token costs. Trade-off: you need sufficient GPU/CPU memory.Simple API -- ollama.chat() and ollama.generate() are the two primary methods. The default import is a pre-configured singleton client; create custom instances with new Ollama() for non-default hosts.Streaming by default in REST, opt-in in SDK -- The REST API streams by default. The SDK returns full responses by default; set stream: true to get an AsyncGenerator. - 05
Core Patterns
The default import is a pre-configured singleton pointing to http://127.0.0.1:11434.
The default import is a pre-configured singleton pointing to http://127.0.0.1:11434.Why good: Minimal setup, default client requires zero configuration, custom client for remote serversWhy bad: Creates a new client instance per request, no reuse, host scattered across codebase
Permission review
Static risk signals and limitations
Network access
The documentation includes network, browsing, or remote request actions.
Generating embeddings for RAG or semantic search without cloud API costsNetwork access
The documentation includes network, browsing, or remote request actions.
host: "http://192.168.1.100:11434",Evidence record
Why each signal appears
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 91/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 21 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Provenance and original SKILL.md
- Repository
- agents-inc/skills
- Skill path
- src/skills/ai-infrastructure-ollama/SKILL.md
- Commit
- 81d43a51211aca12c85dcc16085fa99014ec548e
- License
- MIT
- Collected
- 2026-08-25
- Default branch
- main
View the original SKILL.md
Ollama Patterns
Quick Guide: Use the
ollamanpm package to run LLMs locally. Useollama.chat()for conversations andollama.generate()for single prompts. Enable streaming withstream: trueand iterate withfor await. Useformatwith a JSON schema (viazodToJsonSchema) for structured outputs. Usetoolsarray for function calling. Useollama.embed()for embeddings. Models run on your machine -- no API keys required for local use, but be aware of model loading time and memory usage.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST use ollama.chat() for conversations and ollama.generate() for single-prompt completions -- they have different parameter shapes)
(You MUST handle model loading delays -- the first request after a model is loaded takes significantly longer due to model initialization)
(You MUST use zodToJsonSchema() from zod-to-json-schema for structured outputs -- do NOT manually construct JSON schemas)
(You MUST accumulate streamed thinking, content, and tool_calls fields to maintain conversation history in multi-turn interactions)
(You MUST never assume a model is already pulled -- check with ollama.list() or handle errors from missing models gracefully)
</critical_requirements>
Auto-detection: Ollama, ollama, ollama.chat, ollama.generate, ollama.embed, ollama.pull, ollama.list, ollama.show, ollama.delete, ollama.ps, ollama.abort, ollama.create, keep_alive, zodToJsonSchema, OLLAMA_HOST, llama3, mistral, qwen, gemma, phi, deepseek, local LLM
When to use:
- Running LLMs locally for development, testing, or privacy-sensitive workloads
- Building chat applications with local models (Llama, Mistral, Qwen, Gemma, etc.)
- Extracting structured data from text or images using local models with JSON schemas
- Implementing tool calling / function calling with locally-hosted models
- Generating embeddings for RAG or semantic search without cloud API costs
- Managing local model lifecycle (pull, list, show, delete, copy)
- Prototyping AI features before committing to a cloud provider
Key patterns covered:
- Client setup (default and custom instances)
- Chat completions (
ollama.chat) and text generation (ollama.generate) - Streaming with
for awaitand accumulated state - Structured output with
format+zodToJsonSchema - Tool calling with
toolsarray and multi-turn tool loops - Vision / multimodal inputs with
imagesparameter - Embeddings with
ollama.embed() - Model management (pull, list, show, delete, copy, ps)
- OpenAI-compatible endpoint for drop-in migration
When NOT to use:
- Production workloads requiring guaranteed uptime and SLAs -- use a cloud LLM provider
- Multi-provider applications where you need to switch between OpenAI, Anthropic, Google -- use a unified provider SDK
- Applications requiring the latest proprietary models (GPT-5, Claude) -- those are cloud-only
Examples Index
- Core: Setup, Chat & Generate -- Client init, chat, generate, streaming, error handling
- Tool Calling -- Tool definitions, single/parallel calls, multi-turn agent loops
- Structured Output -- JSON schema via Zod, vision extraction
- Embeddings & Vision -- Embeddings, image analysis, multimodal
- Model Management -- Pull, list, show, delete, copy, ps
- Quick API Reference -- Method signatures, options, response types, model names
Philosophy
The Ollama JavaScript library is a thin client over Ollama's local REST API (default http://127.0.0.1:11434). It provides direct access to locally-running open-source LLMs with zero cloud dependencies.
Core principles:
- Local-first -- Models run on your hardware. No API keys required for local use, complete data privacy, no per-token costs. Trade-off: you need sufficient GPU/CPU memory.
- Simple API --
ollama.chat()andollama.generate()are the two primary methods. The default import is a pre-configured singleton client; create custom instances withnew Ollama()for non-default hosts. - Streaming by default in REST, opt-in in SDK -- The REST API streams by default. The SDK returns full responses by default; set
stream: trueto get anAsyncGenerator. - Model-agnostic -- The same API works with any Ollama-supported model (Llama, Mistral, Qwen, Gemma, Phi, DeepSeek, etc.). Model capabilities (vision, tool calling, structured output) depend on the model.
- OpenAI-compatible -- Ollama exposes
/v1/chat/completionsand/v1/embeddingsendpoints, allowing the OpenAI SDK to connect withbaseURL: 'http://localhost:11434/v1'.
Core Patterns
Pattern 1: Client Setup
The default import is a pre-configured singleton pointing to http://127.0.0.1:11434.
// lib/ollama.ts -- default client (most common)
import ollama from "ollama";
// Use directly -- connects to localhost:11434
const response = await ollama.chat({
model: "llama3.1",
messages: [{ role: "user", content: "Hello" }],
});
// lib/ollama.ts -- custom client for non-default host
import { Ollama } from "ollama";
const ollama = new Ollama({
host: "http://192.168.1.100:11434",
});
export { ollama };
Why good: Minimal setup, default client requires zero configuration, custom client for remote servers
// BAD: Hardcoding host inline everywhere
import { Ollama } from "ollama";
const response = await new Ollama({ host: "http://192.168.1.100:11434" }).chat({
model: "llama3.1",
messages: [{ role: "user", content: "Hello" }],
});
Why bad: Creates a new client instance per request, no reuse, host scattered across codebase
See: examples/core.md for cloud API setup, custom headers, browser usage
Pattern 2: Chat Completions
Multi-turn conversations with message history. You manage the messages array.
import ollama from "ollama";
const response = await ollama.chat({
model: "llama3.1",
messages: [
{ role: "system", content: "You are a helpful coding assistant." },
{ role: "user", content: "Explain TypeScript generics." },
],
});
console.log(response.message.content);
Why good: Clear message roles, system message for behavior control, direct content access
// BAD: Not checking response, no system message
const res = await ollama.chat({
model: "llama3.1",
messages: [{ role: "user", content: "do something" }],
});
Why bad: No system instruction means unpredictable behavior, vague prompt
See: examples/core.md for multi-turn conversations, model options
Pattern 3: Text Generation
Single-prompt completions without message history. Simpler than chat for one-shot tasks.
import ollama from "ollama";
const response = await ollama.generate({
model: "llama3.1",
prompt: "Write a haiku about TypeScript.",
system: "You are a creative writer.",
});
console.log(response.response);
Why good: Simpler API for one-shot tasks, system parameter instead of message array
See: examples/core.md for generate with images, suffix, raw mode
Pattern 4: Streaming
Set stream: true to get an AsyncGenerator. Iterate with for await.
import ollama from "ollama";
const stream = await ollama.chat({
model: "llama3.1",
messages: [{ role: "user", content: "Explain async/await." }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.message.content);
}
console.log(); // newline
Why good: Progressive output for better UX, memory-efficient for long responses
// BAD: Not consuming the stream
const stream = await ollama.chat({
model: "llama3.1",
messages: [{ role: "user", content: "Hello" }],
stream: true,
});
// Stream never consumed -- response is lost
Why bad: Stream must be consumed via iteration, otherwise the response is silently lost
See: examples/core.md for generate streaming, abort, thinking mode streaming
Pattern 5: Structured Output with Zod
Use format with a JSON schema to constrain model output. Use zodToJsonSchema() from zod-to-json-schema to convert Zod schemas.
import ollama from "ollama";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
const Country = z.object({
name: z.string(),
capital: z.string(),
languages: z.array(z.string()),
});
type Country = z.infer<typeof Country>;
const response = await ollama.chat({
model: "llama3.1",
messages: [
{
role: "user",
content: "Tell me about France. Respond in JSON.",
},
],
format: zodToJsonSchema(Country),
});
const country: Country = Country.parse(JSON.parse(response.message.content));
console.log(country.capital); // "Paris"
Why good: Type-safe output via Zod, JSON schema constrains model output, parse validates response
// BAD: Using format: 'json' without a schema
const response = await ollama.chat({
model: "llama3.1",
messages: [{ role: "user", content: "Tell me about France as JSON" }],
format: "json",
});
// No schema enforcement -- model can return any JSON shape
Why bad: format: 'json' only ensures valid JSON syntax, not structure -- use a JSON schema for reliable extraction
See: examples/structured-output.md for vision extraction, complex schemas
Pattern 6: Tool Calling
Define tools the model can request. Handle tool_calls in responses and feed results back.
import ollama from "ollama";
const tools = [
{
type: "function" as const,
function: {
name: "get_weather",
description: "Get the current weather for a city",
parameters: {
type: "object",
required: ["city"],
properties: {
city: { type: "string", description: "City name" },
},
},
},
},
];
const response = await ollama.chat({
model: "llama3.1",
messages: [{ role: "user", content: "What is the weather in Tokyo?" }],
tools,
});
if (response.message.tool_calls?.length) {
for (const toolCall of response.message.tool_calls) {
console.log(`Call: ${toolCall.function.name}`);
console.log(`Args:`, toolCall.function.arguments);
}
}
Why good: Standard tool schema format, checks for tool_calls before processing, arguments already parsed (not stringified JSON)
See: examples/tools.md for multi-turn tool loops, streaming tool calls, parallel tools
Pattern 7: Embeddings
Use ollama.embed() for text embeddings. Supports single or batch inputs.
import ollama from "ollama";
const EMBEDDING_MODEL = "nomic-embed-text";
const response = await ollama.embed({
model: EMBEDDING_MODEL,
input: [
"TypeScript is a typed superset of JavaScript.",
"Rust is a systems programming language.",
],
});
console.log(`Vectors: ${response.embeddings.length}`);
console.log(`Dimensions: ${response.embeddings[0].length}`);
Why good: Batch multiple inputs in one call, named constant for model, returns array of number arrays
See: examples/embeddings-vision.md for semantic search, cosine similarity
Pattern 8: Model Management
Pull, list, show, and delete models programmatically.
import ollama from "ollama";
// List available models
const models = await ollama.list();
for (const model of models.models) {
console.log(`${model.name} (${model.size} bytes)`);
}
// Pull a model with progress streaming
const stream = await ollama.pull({ model: "llama3.1", stream: true });
for await (const progress of stream) {
console.log(
`${progress.status}: ${progress.completed ?? 0}/${progress.total ?? 0}`,
);
}
// Show model details
const info = await ollama.show({ model: "llama3.1" });
console.log(`Parameters: ${info.details.parameter_size}`);
console.log(`Quantization: ${info.details.quantization_level}`);
// Delete a model
await ollama.delete({ model: "old-model" });
Why good: Streaming progress for large downloads, programmatic model lifecycle, detailed model metadata
See: examples/model-management.md for copy, create, running models (ps)
Pattern 9: OpenAI-Compatible Endpoint
Ollama exposes /v1/chat/completions and /v1/embeddings that work with the OpenAI SDK.
import OpenAI from "openai";
const OLLAMA_BASE_URL = "http://localhost:11434/v1";
const client = new OpenAI({
baseURL: OLLAMA_BASE_URL,
apiKey: "ollama", // Required by SDK but unused by Ollama
});
const completion = await client.chat.completions.create({
model: "llama3.1",
messages: [{ role: "user", content: "Why is the sky blue?" }],
});
console.log(completion.choices[0].message.content);
Why good: Drop-in replacement for OpenAI SDK code, named constant for URL, easy to switch between local and cloud
When to use: When migrating existing OpenAI SDK code to local models, or when you want to use OpenAI SDK tooling (structured outputs, streaming helpers) with local models
When not to use: For new Ollama-native code, prefer the ollama package directly -- it exposes Ollama-specific features (model management, keep_alive, thinking mode) that the OpenAI compat layer does not
See: reference.md for supported and unsupported OpenAI features
<decision_framework>
Decision Framework
ollama.chat() vs ollama.generate()
Need multi-turn conversation history?
+-- YES -> ollama.chat() (messages array with roles)
+-- NO -> Is it a single prompt completion?
+-- YES -> ollama.generate() (simpler API)
+-- NO -> ollama.chat() (default choice for most use cases)
Native Ollama SDK vs OpenAI-Compatible Endpoint
Do you have existing OpenAI SDK code to migrate?
+-- YES -> Use OpenAI SDK with baseURL: 'http://localhost:11434/v1'
+-- NO -> Do you need Ollama-specific features?
+-- YES -> Use ollama package (model management, keep_alive, thinking, abort)
+-- NO -> Either works, prefer ollama package for new code
Structured Output vs Plain Text
Do you need structured data from the model?
+-- YES -> Use format parameter with zodToJsonSchema()
| +-- Always include "respond in JSON" in the prompt
| +-- Always parse and validate with Zod after receiving response
+-- NO -> Omit format parameter (plain text response)
Model Selection Guidance
What is your task?
+-- General chat / coding -> llama3.1 (8B for speed, 70B for quality)
+-- Fast + small -> phi4-mini, gemma3 (smaller memory footprint)
+-- Code generation -> qwen2.5-coder, deepseek-coder-v2
+-- Vision/multimodal -> llama3.2-vision, gemma3
+-- Embeddings -> nomic-embed-text, all-minilm
+-- Tool calling -> llama3.1, qwen3, mistral
+-- Reasoning/thinking -> qwen3 (with think: true), deepseek-r1
</decision_framework>
<red_flags>
RED FLAGS
High Priority Issues:
- Not handling model loading time -- first request after model load can take 30+ seconds on CPU; show a loading indicator or set
keep_aliveto keep models warm - Using
format: 'json'instead of a JSON schema -- only ensures valid JSON syntax, not structure; always usezodToJsonSchema()for reliable extraction - Not accumulating streamed fields in multi-turn conversations -- you must collect
thinking,content, andtool_callsfrom all chunks to maintain history - Assuming all models support all features -- tool calling, vision, and structured output depend on the model; check model capabilities first
Medium Priority Issues:
- Not setting
keep_alivefor latency-sensitive applications -- models unload after 5 minutes of inactivity by default; setkeep_alive: '30m'orkeep_alive: -1(indefinite) for persistent sessions - Creating new
Ollama()instances per request instead of reusing a singleton client - Not handling
AbortErrorwhen usingollama.abort()-- listening threads throw when streams are cancelled - Ignoring model size vs available memory -- loading a 70B model on 8GB RAM will fail or swap heavily
Common Mistakes:
- Confusing
ollama.chat()andollama.generate()parameters --chatusesmessages[],generateusespromptandsystem - Using
ollama.embeddings()(deprecated) instead ofollama.embed()-- the newerembed()method supports batch inputs - Passing HTTP/HTTPS URLs to
imagesparameter -- Ollama accepts file paths,Uint8Array, or base64-encoded strings, but not remote URLs - Using tool calling with models that do not support it -- not all models handle tools; use Llama 3.1+, Qwen 3, or Mistral for reliable tool calling
- Forgetting to
JSON.parse()the response content when using structured output -- Ollama returns JSON as a string inmessage.content, not a parsed object
Gotchas & Edge Cases:
- Ollama returns tool call arguments as already-parsed objects (not JSON strings like OpenAI) --
toolCall.function.argumentsis an object, not a string - The
keep_aliveparameter accepts both duration strings ('5m','1h') and numbers (seconds) --0unloads immediately,-1keeps loaded indefinitely ollama.abort()cancels ALL active streams for that client instance -- for individual stream cancellation, usestream.abort()on the returned stream object- Model names can include tags (
llama3.1:8b,llama3.1:70b) -- omitting the tag uses the default (usually smallest) - The
thinkparameter enables extended reasoning but only works with models that support it (Qwen 3, DeepSeek R1) -- it adds athinkingfield to the response alongsidecontent - Browser usage requires importing from
ollama/browserinstead ofollama-- the default import uses Node.js-specific APIs - Cloud API access (ollama.com) requires an API key via
Authorization: Bearerheader and settinghost: 'https://ollama.com' - Response includes performance metrics:
total_duration,eval_count,eval_duration(in nanoseconds) -- calculate tokens/second witheval_count / eval_duration * 1e9
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST use ollama.chat() for conversations and ollama.generate() for single-prompt completions -- they have different parameter shapes)
(You MUST handle model loading delays -- the first request after a model is loaded takes significantly longer due to model initialization)
(You MUST use zodToJsonSchema() from zod-to-json-schema for structured outputs -- do NOT manually construct JSON schemas)
(You MUST accumulate streamed thinking, content, and tool_calls fields to maintain conversation history in multi-turn interactions)
(You MUST never assume a model is already pulled -- check with ollama.list() or handle errors from missing models gracefully)
Failure to follow these rules will produce unreliable, poorly-typed, or broken local LLM integrations.
</critical_reminders>
Frequently asked questions
What to verify before installation and use
What does the ai-infrastructure-ollama source document cover?
Quick Guide: Use the ollama npm package to run LLMs locally. Use ollama.chat() for conversations and ollama.generate() for single prompts. Enable streaming with stream: true and iterate with for await. Use format with a JSON schema (via zodToJsonSchema) for structured outputs. U…
How do I install ai-infrastructure-ollama?
The source record exposes this install command: npx skills add https://github.com/agents-inc/skills --skill "src/skills/ai-infrastructure-ollama". Inspect the command and pinned source before running it.
Which permission-related actions were detected?
Static rules flagged network in the source; the page lists the matching lines and excerpts.