kb-intelligence
by JoshWrites
README.md
# KB Intelligence
A local documentation intelligence system for Zendesk Help Centers, built with Claude and Ollama.
It harvests your Help Center content and search data from Zendesk, builds a semantic knowledge graph over it, and gives you a full editorial intelligence layer: content gaps, stale articles, duplicate detection, LLM-powered label taxonomy, and a Claude Desktop integration via MCP.
---
## Why This Exists
Most documentation teams — especially small ones — are flying blind. Your Help Center might have hundreds of articles. You know roughly what's in it. But you don't know:
- **What your users are actually searching for** that you haven't written yet
- **Which articles are stale** and generating support tickets because they're out of date
- **Which articles are near-duplicates** of each other and should be consolidated
- **Whether your label taxonomy** (if you have one) is consistent or riddled with model hallucinations
- **Which high-traffic articles** have negative votes — meaning they exist, users find them, but they don't help
For a solo technical writer or a small team, answering any of these questions manually requires hours of spreadsheet work — if you do it at all. This system answers all of them automatically, continuously, and surfaces them in a dashboard built for editorial decision-making.
### Especially useful for small teams
Large documentation teams have dedicated tooling, content strategists, and analytics staff. Small teams don't. A single technical writer supporting hundreds of articles at a growing SaaS company is the exact user this was built for.
The system runs entirely **on your machine**. There's no SaaS subscription, no data leaves your network, and the only ongoing cost is the Zendesk API calls you were already making. The local LLM stack (Ollama + `llama3.1:8b`) does the heavy lifting on label suggestions and gap analysis without sending your KB content to a cloud API.
The Claude integration layers on top: once the local database is built, Claude can reason over your entire Help Center with full semantic search, gap detection, and graph traversal — giving you a conversational interface to your own documentation.
---
## What It Does
### Pipeline (Python scripts, run once or on a schedule)
1. **Import** — Pulls article HTML, metadata, and engagement data from Zendesk via the REST API and Explore CSV exports
2. **Embed** — Generates semantic embeddings for every article and search query using Ollama (`nomic-embed-text`)
3. **Graph** — Extracts inbound/outbound links, transclusions, and section relationships to build a knowledge graph
4. **Label** — Uses a local LLM to suggest labels for every article based on your approved taxonomy. Corrections and few-shot examples are injected from `data/corrections.json` to keep suggestions consistent
5. **Gaps** — Cross-references zero-click search queries against article embeddings to surface content your users searched for but didn't find
### MCP Server (Claude Desktop integration)
`mcp_server.py` exposes the local database as an MCP server that Claude Desktop can connect to. Tools available to Claude:
| Tool | What it does |
|------|-------------|
| `search_articles` | Semantic search over the full article corpus |
| `get_article` | Retrieve a single article by ID with full metadata |
| `find_similar_articles` | Find articles semantically similar to a given one |
| `label_coverage` | Show which articles lack approved labels |
| `search_query_gaps` | Surface search queries with no good article matches |
| `stale_articles` | List articles by staleness signal (age, votes, ticket rate) |
| `article_graph` | Traverse the knowledge graph for a given article |
| `apply_labels` | Write approved labels back to Zendesk |
| `resolve_article_id` | Resolve a title to a numeric article ID |
With this running, you can ask Claude things like:
- *"Which articles about SSO have the most support tickets after viewing?"*
- *"Find me all articles that link to the getting started guide but don't have an onboarding label."*
- *"What are the most common searches with no article result?"*
- *"Which articles about billing haven't been updated in over a year and have negative votes?"*
### Dashboard (React + FastAPI)
A panel-based editorial dashboard for reviewing the pipeline output without leaving the browser:
| Panel | Purpose |
|-------|---------|
| Overview | Article counts, embedding coverage, label coverage at a glance |
| Label Taxonomy | Browse and review your full label schema |
| Content Gaps | Search queries with poor or no article coverage |
| Article Health | Articles ranked by staleness, votes, and ticket rate |
| Explorer | Interactive knowledge graph: click any article, see its connections |
| Staleness | Articles sorted by last-updated date with engagement signals |
| Label Workflow | Review LLM label suggestions article by article, approve or reject |
| Search | Semantic search with similarity scores and metadata |
| Consolidation | Clusters of near-duplicate articles to consider merging |
| Maintenance | Database refresh controls and pipeline status |
---
## Tech Stack
| Component | Technology |
|-----------|-----------|
| Database | SQLite + [sqlite-vec](https://github.com/asg017/sqlite-vec) for vector search |
| Embeddings | [Ollama](https://ollama.com) (`nomic-embed-text`, 768-dim) |
| LLM | Ollama (`llama3.1:8b`) for local label suggestion |
| Claude integration | [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) |
| API | FastAPI + uvicorn |
| Dashboard | React 19 + Vite + TanStack Query + Tailwind 4 + D3 |
| Tests | pytest (pipeline + API) + Vitest + Playwright (dashboard) |
Everything runs locally. No cloud AI APIs required for the pipeline.
---
## Setup
### Prerequisites
- Python 3.11+
- Node.js 20+
- [Ollama](https://ollama.com) running locally
- A Zendesk account with Help Center enabled and API access
- [Claude Desktop](https://claude.ai/download) (for the MCP integration)
### 1. Clone and install
```bash
git clone https://github.com/your-github-username/zendesk-kb-intelligence.git
cd zendesk-kb-intelligence
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cd dashboard && npm install && cd ..
```
### 2. Configure
Copy the example config and fill in your Zendesk credentials:
```bash
cp config.example.json config.json
```
Edit `config.json`:
```json
{
"zendesk": {
"subdomain": "your-subdomain",
"email": "admin@your-company.com",
"api_token": "your_api_token_here",
"locale": "en-us",
"help_center_domain": "your-subdomain.zendesk.com"
},
"database": { "path": "kb.db" },
"ollama": {
"host": "http://localhost:11434",
"embed_model": "nomic-embed-text",
"eval_model": "llama3.1:8b"
}
}
```
Configure the dashboard:
```bash
cp dashboard/.env.example dashboard/.env
# Edit dashboard/.env with your Zendesk subdomain
```
### 3. Pull Ollama models
```bash
ollama pull nomic-embed-text
ollama pull llama3.1:8b
```
### 4. Run the pipeline
```bash
# Initialize the database
python init_db.py
python init_vec.py
# Pull content from Zendesk
python harvest.py
# Load engagement data (export CSVs from Zendesk Explore first — see below)
python load_csvs.py
# Build embeddings
python embed_articles.py
python embed_queries.py
# Derive label schema from your app structure
python derive_label_schema.py
# Review and approve labels in data/label_schema.json, then:
# Run label suggestions (loops until all articles are processed)
bash run_until_done.sh
# Detect content gaps
python gap_detection.py
# Build the knowledge graph
python extract_links.py
python resolve_transclusions.py
```
### 5. Connect Claude Desktop
Add the MCP server to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"kb-intelligence": {
"command": "/path/to/.venv/bin/python",
"args": ["/path/to/zendesk-kb-intelligence/mcp_server.py"],
"env": {
"DB_PATH": "/path/to/kb.db"
}
}
}
}
```
### 6. Start the dashboard
```bash
# Terminal 1 — API
source .venv/bin/activate
uvicorn api.main:app --reload --port 8765
# Terminal 2 — Dashboard
cd dashboard && npm run dev
```
Open [http://localhost:5173](http://localhost:5173).
---
## Zendesk Explore CSV Exports
`load_csvs.py` expects these reports exported from Zendesk Explore:
| Report | Expected filename pattern |
|--------|--------------------------|
| Article engagement (views, votes) | `article_engagement*.csv` |
| Deflection drilldown | `deflection_drilldown*.csv` |
| Quick answers | `quick_answers*.csv` |
| Search queries overview | `search_queries_overview*.csv` |
| Search clicks | `search_clicks*.csv` |
| Search no results | `search_no_results*.csv` |
Export these to `data/exports/` (gitignored).
---
## Label Schema
The label system has two layers:
**Layer 1 — Architectural:** Derived from your product's navigation structure. These reflect how your product is organized (tabs, sections, feature areas). Defined in `LAYER_1_LABELS` in `derive_label_schema.py` — edit this to match your product.
**Layer 2 — Intent:** Derived by clustering your actual search query embeddings. These reflect how your *users* talk about your product — often different from how your documentation is organized.
The two layers together form a vocabulary that satisfies both content organization and search discoverability.
To customize for your product:
1. Edit `LAYER_1_LABELS` in `derive_label_schema.py` with your top-level navigation
2. Run `python derive_label_schema.py`
3. Review `data/label_schema.json` — set status, label, and description for Layer 2 candidates
4. Set `reviewed_by` and `reviewed_at` in `label_schema.json`
5. Commit `label_schema.json` and run the embedding + suggestion pipeline
---
## Running Tests
```bash
# Python pipeline tests
source .venv/bin/activate
pytest tests/ -v
# API tests (requires a populated kb.db)
pytest api/tests/ -v
# Dashboard unit tests
cd dashboard && npm run test:run
# Dashboard e2e tests (requires running dev server)
cd dashboard && npm run test:e2e
```
---
## Project Structure
```
.
├── schema.sql # SQLite schema
├── init_db.py # DB initialization
├── harvest.py # Zendesk API → DB
├── load_csvs.py # Zendesk Explore CSVs → DB
├── embed_articles.py # Article embeddings (Ollama)
├── embed_queries.py # Search query embeddings
├── derive_label_schema.py # Label taxonomy derivation
├── suggest_labels.py # LLM label suggestions
├── gap_detection.py # Content gap detection
├── extract_links.py # Knowledge graph: links
├── resolve_transclusions.py # Knowledge graph: transclusions
├── apply_labels.py # Write labels back to Zendesk
├── mcp_server.py # Claude Desktop MCP integration
├── refresh.py # Incremental sync (in progress)
├── config.py # Config loader
├── config.example.json # Config template
├── .env.example # Environment variable template
├── data/
│ ├── label_schema.json # Approved label taxonomy
│ └── corrections.json # LLM correction rules
├── api/ # FastAPI backend
│ ├── main.py
│ ├── routers/
│ └── tests/
├── dashboard/ # React dashboard
│ ├── src/
│ ├── .env.example
│ └── .env.test
└── tests/ # Pipeline test suite
```
---
## Adapting for Your Help Center
This repo is a working template, not an abstract framework. It was built for a real Help Center and then generalized. To make it yours:
1. **Label schema** — The biggest customization. Edit `LAYER_1_LABELS` in `derive_label_schema.py` to reflect your product's navigation. Everything else flows from the schema you define.
2. **Few-shot examples** — `suggest_labels.py` contains `FEW_SHOT_EXAMPLES`: real articles with correct labels that teach the LLM how to apply your taxonomy. Replace or extend these with examples from your own KB for best results.
3. **Corrections** — As you run the pipeline, you'll find systematic errors (the LLM applies a label too broadly, invents compound labels, etc.). Log them in `data/corrections.json`. The pipeline injects these as rules on every run.
4. **Model** — The pipeline uses `llama3.1:8b` by default. If you have a larger machine, swap in `llama3.1:70b` or any other Ollama-supported model in `config.json`.
---
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues