# keyword-cluster

Keyword clustering and search-intent intelligence for SEO, PPC and content strategy. cluster groups a raw keyword list into topical clusters using a self-contained vectorizer (stemmed token overlap +...


**AI keyword-intelligence microservice** for SEO, PPC and content strategy. Turns a raw keyword list
into topical clusters, search-intent groups, deduped canonicals, seed expansions and ranking-difficulty
scores — all with a **self-contained vectorizer** (character-n-gram cosine + stemmed token overlap, the
"embeddings concept" implemented offline, no ML model, no external API).

Every tool has a deterministic core that runs fully **offline**. The generative/analytical tools
(`cluster`, `expand`) also wire an optional LLM path that enriches when a model is reachable and
silently falls back to the heuristic — results carry `{ mode: 'heuristic' | 'llm' }`.

## Tools

| Tool | Input | What it does |
|---|---|---|
| `cluster` | `keywords` | Groups keywords into topical clusters via fused cosine + token-overlap similarity; labels each by its most-central keyword; reports cohesion + outliers. Optional LLM cluster labels. |
| `intentGroup` | `keywords` | Classifies each keyword into `informational` / `commercial` / `navigational` / `transactional` from signal-word lexicons; returns groups + distribution. |
| `dedupeSimilar` | `keywords` | Collapses near-duplicate / paraphrase keywords above a similarity `threshold`, keeping one canonical per group. |
| `expand` | `seed` | Generates variant queries around a seed: prefix/suffix modifiers, question forms, comparisons, buyer-stage, long-tail. Optional LLM variants. |
| `difficultyEstimate` | `keyword` or `keywords` | Scores ranking difficulty 0-100 with `easy`/`medium`/`hard` bands from word count, intent, head-vs-long-tail and modifier signals; transparent factor list. |

## Usage

```js
import pack from './index.js';

await pack.adapters.cluster({
  keywords: ['best running shoes', 'top running shoes', 'buy trail shoes', 'trail running shoes review'],
  options: { threshold: 0.3 },
});

pack.adapters.intentGroup({ keywords: ['how to tie shoes', 'buy nike shoes', 'nike login'] });

pack.adapters.difficultyEstimate({ keyword: 'shoes' });
```

Each tool takes ONE args object (maps 1:1 to an HTTP POST body). Invalid input throws `TypeError`.

## Options

`options`: `threshold` (0-1 similarity for `cluster`/`dedupeSimilar`), `ngram` (2-4 char-gram size),
`minClusterSize`, `maxClusters`, `limit` (expand cap), `modifiers` (extra expansion suffixes),
`narrate` (force-try the LLM label/variant path).

## DRY boundaries

- This OWNS **keyword-list intelligence** (clustering, intent, dedupe, expansion, difficulty).
- It does NOT audit HTML/meta or build keyword briefs — that's the `seo` pack.
- The tiny vectorizer is inlined and keyword-specific on purpose; it does not import the generic
  `embeddings` pack or `a-transformation` vector tools (no cross-pack imports except `../_shared/llm.js`).


---
Source: shared/engines/adapters/domain/keyword-cluster/README.md
Canonical: https://docs.leumas.tech/p/adapters/domain/keyword-cluster
