Algolia core workflow a
425 plugins, 2,810 skills, 200 agents for Claude Code. Open-source marketplace at tonsofskills.com with the ccpi CLI package manager.
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill algolia-core-workflow-aAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
'Implement Algolia search with filters, facets, highlighting, and pagination.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
5.7 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it
Algolia Core Workflow A — Search & Filtering
Overview
Primary Algolia workflow: full-text search with filters, faceted navigation, hit highlighting, and pagination. Uses searchSingleIndex (v5) with real Algolia search parameters.
Prerequisites
- Completed
algolia-install-authandalgolia-hello-worldsetup - Index populated with records (see
algolia-hello-world) - Index settings configured with
searchableAttributesandattributesForFaceting
Instructions
Step 1: Configure Index for Filtering
import { algoliasearch } from 'algoliasearch';
const client = algoliasearch(process.env.ALGOLIA_APP_ID!, process.env.ALGOLIA_ADMIN_KEY!);
await client.setSettings({
indexName: 'products',
indexSettings: {
// What to search (ordered = priority matters)
searchableAttributes: ['name', 'description', 'brand', 'category'],
// What to filter/facet on — prefix with filterOnly() if no facet counts needed
attributesForFaceting: [
'searchable(brand)', // Searchable facet: users can search within brand values
'category', // Regular facet: shown in facet panels
'filterOnly(price)', // Filter only: no counts computed, saves CPU
'filterOnly(in_stock)',
],
// Custom ranking: tie-breaker after Algolia's relevance ranking
customRanking: ['desc(sales_count)', 'desc(rating)'],
// What comes back in hits
attributesToRetrieve: ['name', 'brand', 'price', 'image_url', 'category'],
attributesToHighlight: ['name', 'description'],
attributesToSnippet: ['description:30'], // 30-word snippet
},
});
Step 2: Search with Filters
// Algolia filter syntax uses SQL-like expressions
const { hits, nbHits, facets } = await client.searchSingleIndex({
indexName: 'products',
searchParams: {
query: 'running shoes',
// Numeric/boolean/string filters
filters: 'price < 150 AND in_stock = true',
// OR: facetFilters for UI-driven filtering (array = OR, nested = AND)
// facetFilters: [['category:shoes', 'category:sneakers'], ['brand:Nike']],
// ^ shoes OR sneakers, AND brand is Nike
// Numeric range filters
numericFilters: ['price >= 50', 'price <= 150'],
// Request facet counts for these attributes
facets: ['category', 'brand'],
// Pagination
hitsPerPage: 20,
page: 0,
// Highlighting
highlightPreTag: '<mark>',
highlightPostTag: '</mark>',
},
});
console.log(`${nbHits} results found`);
// Access facet counts for building filter UI
// facets = { category: { shoes: 42, sneakers: 18 }, brand: { Nike: 30, Adidas: 25 } }
for (const [facetName, values] of Object.entries(facets || {})) {
console.log(`${facetName}:`);
for (const [value, count] of Object.entries(values)) {
console.log(` ${value}: ${count}`);
}
}
Step 3: Display Highlighted Results
hits.forEach(hit => {
// _highlightResult contains highlighted versions of each field
const highlighted = hit._highlightResult;
const name = highlighted?.name?.value || hit.name;
const snippet = hit._snippetResult?.description?.value || '';
console.log(`${name} — $${hit.price}`);
if (snippet) console.log(` ${snippet}`);
});
Step 4: Implement Pagination
async function paginatedSearch(query: string, page: number = 0) {
const { hits, nbHits, nbPages, hitsPerPage } = await client.searchSingleIndex({
indexName: 'products',
searchParams: {
query,
hitsPerPage: 20,
page,
},
});
return {
hits,
totalHits: nbHits,
totalPages: nbPages,
currentPage: page,
hasMore: page < nbPages - 1,
};
}
Error Handling
| Error | Cause | Solution |
|---|---|---|
Invalid filter syntax | Malformed filters string | Check filter syntax: field:value, field < N, use AND/OR/NOT |
Attribute not valid for filtering | Field not in attributesForFaceting | Add field to attributesForFaceting in settings |
0 results unexpectedly | Typo tolerance may be disabled | Check typoTolerance setting; verify data is indexed |
| Stale results after update | Didn't wait for task | Use await client.waitForTask() after indexing |
Examples
Multi-Index Search (Federated)
const { results } = await client.search({
requests: [
{ indexName: 'products', query: 'laptop', hitsPerPage: 5 },
{ indexName: 'articles', query: 'laptop', hitsPerPage: 3 },
],
});
// results[0].hits = product hits, results[1].hits = article hits
Search with Optional Filters (boost, not require)
const { hits } = await client.searchSingleIndex({
indexName: 'products',
searchParams: {
query: 'shoes',
optionalFilters: ['brand:Nike'], // Nike products ranked higher but not required
},
});
Resources
Next Steps
For indexing and data sync workflows, see algolia-core-workflow-b.