
Embeddings
- 15 installs
- 610 repo stars
- Updated June 26, 2026
- alsk1992/cloddsbot
Embeddings is a Claude Code skill that configures embedding providers, vector storage, and semantic search for the clodds agent framework.
About
Embeddings is a skill for the clodds framework that configures embedding providers, manages vector storage, and runs semantic search. A developer uses /embeddings commands or the createEmbeddingsService TypeScript API to pick a provider (OpenAI, Voyage, Cohere, or a local model), generate and store vectors, compare text similarity, and search a collection. It supports caching and batching to reduce cost.
- Configures embedding providers (OpenAI, Voyage, Cohere, local Transformers.js) and vector storage
- Generates single and batched embeddings and runs semantic search with score thresholds
- Caches embeddings to SQLite with hit-rate stats to cut redundant API calls
Embeddings by the numbers
- 15 all-time installs (skills.sh)
- Ranked #11,187 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
embeddings capabilities & compatibility
Cloud providers charge per token (e.g. OpenAI $0.02/1M); the local Transformers.js model runs free with no API key.
- Capabilities
- embeddings · semantic search · vector storage · text similarity
- Works with
- openai
- Use cases
- memory · research
- Pricing
- Bring your own API key
What embeddings says it does
Configure embedding providers, manage vector storage, and perform semantic search.
No API key required - runs locally via @xenova/transformers
npx skills add https://github.com/alsk1992/cloddsbot --skill embeddingsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 15 |
|---|---|
| repo stars | ★ 610 |
| Last updated | June 26, 2026 |
| Repository | alsk1992/cloddsbot ↗ |
What it does
Configure embedding providers and vector storage to generate embeddings and run semantic search inside an agent.
Who is it for?
Adding provider-agnostic embeddings, vector storage, and semantic search to an agent.
When should I use this skill?
You need to generate embeddings, store vectors, or run semantic search in an agent.
What you get
Configured embedding providers with batching, caching, similarity scoring, and semantic search over stored collections.
By the numbers
- 4 providers: OpenAI, Voyage, Cohere, local Transformers.js
- text-embedding-3-small produces 1536 dimensions
Files
Embeddings - Complete API Reference
Configure embedding providers, manage vector storage, and perform semantic search.
---
Chat Commands
View Config
/embeddings Show current settings
/embeddings status Provider status
/embeddings stats Cache statisticsConfigure Provider
/embeddings provider openai Use OpenAI embeddings
/embeddings provider voyage Use Voyage AI
/embeddings provider local Use local model
/embeddings model text-embedding-3-small Set modelCache Management
/embeddings cache stats View cache stats
/embeddings cache clear Clear cache
/embeddings cache size Total cache sizeTesting
/embeddings test "sample text" Generate test embedding
/embeddings similarity "text1" "text2" Compare similarity---
TypeScript API Reference
Create Embeddings Service
import { createEmbeddingsService } from 'clodds/embeddings';
const embeddings = createEmbeddingsService({
// Provider
provider: 'openai', // 'openai' | 'voyage' | 'local' | 'cohere'
apiKey: process.env.OPENAI_API_KEY,
// Model
model: 'text-embedding-3-small',
dimensions: 1536,
// Caching
cache: true,
cacheBackend: 'sqlite',
cachePath: './embeddings-cache.db',
// Batching
batchSize: 100,
maxConcurrent: 5,
});Generate Embeddings
// Single text
const embedding = await embeddings.embed('Hello world');
console.log(`Dimensions: ${embedding.length}`);
// Multiple texts (batched)
const vectors = await embeddings.embedBatch([
'First document',
'Second document',
'Third document',
]);Semantic Search
// Search against stored vectors
const results = await embeddings.search({
query: 'trading strategies',
collection: 'documents',
limit: 10,
threshold: 0.7,
});
for (const result of results) {
console.log(`${result.text} (score: ${result.score})`);
}Similarity
// Compare two texts
const score = await embeddings.similarity(
'The cat sat on the mat',
'A feline rested on the rug'
);
console.log(`Similarity: ${score}`); // 0.0 - 1.0Store Vectors
// Store embedding with metadata
await embeddings.store({
collection: 'documents',
id: 'doc-1',
text: 'Original text',
embedding: vector,
metadata: {
source: 'wiki',
date: '2024-01-01',
},
});
// Store batch
await embeddings.storeBatch({
collection: 'documents',
items: [
{ id: 'doc-1', text: 'First doc' },
{ id: 'doc-2', text: 'Second doc' },
],
});Cache Management
// Get cache stats
const stats = await embeddings.getCacheStats();
console.log(`Cached: ${stats.count} embeddings`);
console.log(`Size: ${stats.sizeMB} MB`);
console.log(`Hit rate: ${stats.hitRate}%`);
// Clear cache
await embeddings.clearCache();
// Clear specific entries
await embeddings.clearCache({ olderThan: '7d' });Provider Configuration
// Switch provider
embeddings.setProvider('voyage', {
apiKey: process.env.VOYAGE_API_KEY,
model: 'voyage-large-2',
});
// Use local model (Transformers.js)
// No API key required - runs locally via @xenova/transformers
embeddings.setProvider('local', {
model: 'Xenova/all-MiniLM-L6-v2', // 384 dimensions
});---
Providers
| Provider | Models | Quality | Speed | Cost |
|---|---|---|---|---|
| OpenAI | text-embedding-3-small/large | Excellent | Fast | $0.02/1M |
| Voyage | voyage-large-2 | Excellent | Fast | $0.02/1M |
| Cohere | embed-english-v3 | Good | Fast | $0.10/1M |
| Local (Transformers.js) | Xenova/all-MiniLM-L6-v2 | Good | Medium | Free |
---
Models
OpenAI
| Model | Dimensions | Best For |
|---|---|---|
text-embedding-3-small | 1536 | General use |
text-embedding-3-large | 3072 | High accuracy |
Voyage
| Model | Dimensions | Best For |
|---|---|---|
voyage-large-2 | 1024 | General use |
voyage-code-2 | 1536 | Code search |
---
Use Cases
Semantic Memory Search
// Store user memories
await embeddings.store({
collection: 'memories',
id: 'mem-1',
text: 'User prefers conservative trading',
});
// Search memories
const relevant = await embeddings.search({
query: 'what is user risk preference',
collection: 'memories',
limit: 5,
});Document Similarity
// Find similar documents
const similar = await embeddings.findSimilar({
text: 'How to trade options',
collection: 'docs',
limit: 5,
});---
Best Practices
1. Use caching — Avoid redundant API calls 2. Batch requests — More efficient than single calls 3. Choose dimensions wisely — Balance quality vs storage 4. Monitor costs — Embeddings can add up 5. Local for development — Use local model to save costs
/**
* Embeddings CLI Skill
*
* Commands:
* /embed text <text> - Generate embedding for text
* /embed search <query> - Semantic search across cached embeddings
* /embed similarity <a> | <b> - Compare two texts for similarity
* /embed cache stats - Show embedding cache statistics
* /embed cache clear - Clear embedding cache
* /embed config - Show current embedding configuration
*/
import {
createEmbeddingsService,
type EmbeddingsService,
type EmbeddingConfig,
} from '../../../embeddings/index';
import { logger } from '../../../utils/logger';
import { formatHelp } from '../../help.js';
import { wrapSkillError } from '../../errors.js';
let service: EmbeddingsService | null = null;
let serviceInitPromise: Promise<EmbeddingsService | null> | null = null;
async function initService(): Promise<EmbeddingsService | null> {
if (service) return service;
try {
// Import database module and create instance
const { createDatabase } = await import('../../../db/index');
const db = createDatabase();
const config: Partial<EmbeddingConfig> = {};
if (process.env.OPENAI_API_KEY) {
config.provider = 'openai';
config.apiKey = process.env.OPENAI_API_KEY;
} else if (process.env.VOYAGE_API_KEY) {
config.provider = 'voyage';
config.apiKey = process.env.VOYAGE_API_KEY;
}
// Default: uses local transformers.js (no API key needed)
service = createEmbeddingsService(db, config);
return service;
} catch (err) {
logger.warn({ err }, 'Failed to initialize embeddings service');
return null;
}
}
function getService(): EmbeddingsService | null {
// Return cached service if available
if (service) return service;
// Trigger async init if not started
if (!serviceInitPromise) {
serviceInitPromise = initService();
}
return null; // Will be available after init
}
async function getServiceAsync(): Promise<EmbeddingsService | null> {
if (service) return service;
if (!serviceInitPromise) {
serviceInitPromise = initService();
}
return serviceInitPromise;
}
async function handleEmbed(text: string): Promise<string> {
const svc = await getServiceAsync();
if (!svc) return 'Embeddings service not available. Check database initialization.';
try {
const vector = await svc.embed(text);
return `**Embedding Generated**\n\n` +
`Text: "${text.slice(0, 100)}${text.length > 100 ? '...' : ''}"\n` +
`Dimensions: ${vector.length}\n` +
`Sample values: [${vector.slice(0, 5).map(v => v.toFixed(6)).join(', ')}, ...]`;
} catch (error) {
return `Error generating embedding: ${error instanceof Error ? error.message : String(error)}`;
}
}
async function handleSimilarity(input: string): Promise<string> {
const svc = await getServiceAsync();
if (!svc) return 'Embeddings service not available. Check database initialization.';
const parts = input.split('|').map(s => s.trim());
if (parts.length < 2) {
return 'Usage: /embed similarity <text a> | <text b>';
}
try {
const [vecA, vecB] = await svc.embedBatch([parts[0], parts[1]]);
const score = svc.cosineSimilarity(vecA, vecB);
return `**Similarity Analysis**\n\n` +
`Text A: "${parts[0].slice(0, 60)}${parts[0].length > 60 ? '...' : ''}"\n` +
`Text B: "${parts[1].slice(0, 60)}${parts[1].length > 60 ? '...' : ''}"\n\n` +
`Cosine Similarity: ${(score * 100).toFixed(2)}%\n` +
`Interpretation: ${score > 0.8 ? 'Very similar' : score > 0.5 ? 'Moderately similar' : score > 0.3 ? 'Somewhat related' : 'Not very similar'}`;
} catch (error) {
return `Error computing similarity: ${error instanceof Error ? error.message : String(error)}`;
}
}
async function handleCacheStats(): Promise<string> {
const svc = await getServiceAsync();
const hasOpenAI = !!process.env.OPENAI_API_KEY;
const hasVoyage = !!process.env.VOYAGE_API_KEY;
const provider = hasOpenAI ? 'OpenAI' : hasVoyage ? 'Voyage' : 'Local (transformers.js)';
const model = hasOpenAI ? 'text-embedding-3-small' : hasVoyage ? 'voyage-2' : 'Xenova/all-MiniLM-L6-v2';
return `**Embedding Cache**\n\n` +
`Provider: ${provider}\n` +
`Model: ${model}\n` +
`Status: ${svc ? 'Active' : 'Not initialized'}`;
}
async function handleConfig(): Promise<string> {
const hasOpenAI = !!process.env.OPENAI_API_KEY;
const hasVoyage = !!process.env.VOYAGE_API_KEY;
const provider = hasOpenAI ? 'OpenAI' : hasVoyage ? 'Voyage' : 'Local (transformers.js)';
const model = hasOpenAI ? 'text-embedding-3-small' : hasVoyage ? 'voyage-2' : 'Xenova/all-MiniLM-L6-v2';
const dims = hasOpenAI ? '1536' : hasVoyage ? '1024' : '384';
return `**Embeddings Configuration**\n\n` +
`Provider: ${provider}\n` +
`Model: ${model}\n` +
`Dimensions: ${dims}\n` +
`Cache: SQLite-backed with in-memory layer\n` +
`API Key: ${hasOpenAI ? 'OpenAI set' : hasVoyage ? 'Voyage set' : 'None (using local)'}`;
}
export async function execute(args: string): Promise<string> {
const parts = args.trim().split(/\s+/);
const cmd = parts[0]?.toLowerCase() || 'help';
const rest = parts.slice(1);
try {
switch (cmd) {
case 'text':
case 'embed':
if (rest.length === 0) return 'Usage: /embed text <text>';
return handleEmbed(rest.join(' '));
case 'search':
if (rest.length === 0) return 'Usage: /embed search <query>';
return handleEmbed(rest.join(' ')); // Same as embed for now
case 'similarity':
case 'compare':
if (rest.length === 0) return 'Usage: /embed similarity <text a> | <text b>';
return handleSimilarity(rest.join(' '));
case 'cache':
if (rest[0] === 'clear') {
const svc = await initService();
if (svc) svc.clearCache();
return 'Embedding cache cleared.';
}
return handleCacheStats();
case 'provider': {
const providerArg = rest[0]?.toLowerCase();
if (!providerArg) {
const hasOpenAI = !!process.env.OPENAI_API_KEY;
const hasVoyage = !!process.env.VOYAGE_API_KEY;
const current = hasOpenAI ? 'openai' : hasVoyage ? 'voyage' : 'local';
return `**Current Embedding Provider:** ${current}\n\nAvailable: openai, voyage, local\n\nTo switch provider, set the appropriate env var:\n OPENAI_API_KEY - for OpenAI\n VOYAGE_API_KEY - for Voyage AI\n (no key needed) - for local transformers.js`;
}
const validProviders = ['openai', 'voyage', 'local'];
if (!validProviders.includes(providerArg)) {
return `Unknown provider "${providerArg}". Available: ${validProviders.join(', ')}`;
}
if (providerArg === 'openai' && !process.env.OPENAI_API_KEY) {
return `To use OpenAI embeddings, set OPENAI_API_KEY env var first.`;
}
if (providerArg === 'voyage' && !process.env.VOYAGE_API_KEY) {
return `To use Voyage embeddings, set VOYAGE_API_KEY env var first.`;
}
// Reinitialize service with new provider
service = null;
serviceInitPromise = null;
return `Provider set to **${providerArg}**. Service will reinitialize on next use.`;
}
case 'model': {
const modelArg = rest.join(' ');
if (!modelArg) {
const hasOpenAI = !!process.env.OPENAI_API_KEY;
const hasVoyage = !!process.env.VOYAGE_API_KEY;
const model = hasOpenAI ? 'text-embedding-3-small' : hasVoyage ? 'voyage-2' : 'Xenova/all-MiniLM-L6-v2';
return `**Current Embedding Model:** ${model}\n\nModels by provider:\n OpenAI: text-embedding-3-small, text-embedding-3-large\n Voyage: voyage-2, voyage-large-2, voyage-code-2\n Local: Xenova/all-MiniLM-L6-v2`;
}
return `Model preference noted: **${modelArg}**.\n\nTo apply, set the appropriate env var and restart. Model selection is determined by the active provider configuration.`;
}
case 'test': {
const testText = rest.join(' ') || 'Hello, world!';
const svc = await getServiceAsync();
if (!svc) return 'Embeddings service not available. Check database initialization.';
try {
const vector = await svc.embed(testText);
return `**Embedding Test**\n\n` +
`Input: "${testText.slice(0, 100)}${testText.length > 100 ? '...' : ''}"\n` +
`Dimensions: ${vector.length}\n` +
`First 5 values: [${vector.slice(0, 5).map(v => v.toFixed(6)).join(', ')}]\n` +
`Last 5 values: [${vector.slice(-5).map(v => v.toFixed(6)).join(', ')}]\n` +
`Norm: ${Math.sqrt(vector.reduce((sum, v) => sum + v * v, 0)).toFixed(6)}`;
} catch (error) {
return `Test failed: ${error instanceof Error ? error.message : String(error)}`;
}
}
case 'config':
case 'status':
return handleConfig();
case 'help':
default:
return formatHelp({
name: 'Embeddings',
emoji: '\u{1F9E0}',
description: 'Vector embeddings for semantic search — OpenAI, Voyage, or local transformers.js',
sections: [
{
title: 'Generate',
commands: [
{ cmd: '/embed text <text>', description: 'Generate embedding vector' },
{ cmd: '/embed search <query>', description: 'Semantic search' },
],
},
{
title: 'Compare',
commands: [
{ cmd: '/embed similarity <a> | <b>', description: 'Compare two texts' },
],
},
{
title: 'Cache',
commands: [
{ cmd: '/embed cache stats', description: 'Cache statistics' },
{ cmd: '/embed cache clear', description: 'Clear cache' },
],
},
{
title: 'Config',
commands: [
{ cmd: '/embed config', description: 'Show configuration' },
{ cmd: '/embed provider [name]', description: 'Set/show provider (openai/voyage/local)' },
{ cmd: '/embed model [name]', description: 'Set/show embedding model' },
{ cmd: '/embed test [text]', description: 'Test embed text and show vector info' },
],
},
],
examples: [
'/embed text What is prediction market arbitrage?',
'/embed similarity crypto markets | prediction markets',
'/embed config',
],
envVars: [
{ name: 'OPENAI_API_KEY', description: 'Use OpenAI text-embedding-3-small', required: false },
{ name: 'VOYAGE_API_KEY', description: 'Use Voyage AI voyage-2', required: false },
],
seeAlso: [
{ cmd: '/research', description: 'Research with embedded context' },
{ cmd: '/ai-strategy', description: 'AI-powered strategy discovery' },
{ cmd: '/search-config', description: 'Configure search settings' },
],
notes: [
'Shortcuts: /embed is an alias for /embeddings',
'No API key needed — falls back to local transformers.js (384 dims)',
],
});
}
} catch (error) {
return wrapSkillError('Embeddings', cmd || 'command', error);
}
}
export default {
name: 'embeddings',
description: 'Vector embeddings for semantic search - OpenAI or local transformers.js',
commands: ['/embeddings', '/embed'],
handle: execute,
};