Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Self-hosted semantic search and text mining platform
.claude/skills/brycewang-stanford-open-semantic-search-guide/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 16% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 10% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 46% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 52% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 35% | 0% |
Open Semantic Search is a self-hosted search and text mining platform that combines full-text search (Apache Solr) with semantic analysis — entity extraction, named entity recognition, text classification, and knowledge graph building. Process and search across documents (PDF, DOCX, emails) with faceted navigation and visual analytics. Ideal for researchers needing private, on-premise document search over large paper collections.
bash# Docker deployment (recommended) git clone https://github.com/opensemanticsearch/open-semantic-search.git cd open-semantic-search docker-compose up -d # Access web UI at http://localhost:8080 # Admin panel at http://localhost:8080/admin
Documents (PDF, DOCX, HTML, email)
↓
Connector/Crawler (file system, web, IMAP)
↓
ETL Pipeline
├── Text extraction (Apache Tika)
├── OCR (Tesseract, for scanned docs)
├── NER (spaCy, Stanford NER)
├── Entity linking (knowledge base)
└── Classification (custom models)
↓
Apache Solr (full-text index + facets)
↓
Web UI (search, browse, visualize)bash# Index a directory of papers curl -X POST "http://localhost:8080/api/index" \ -H "Content-Type: application/json" \ -d '{"path": "/data/papers/", "recursive": true}' # Index single file curl -X POST "http://localhost:8080/api/index" \ -H "Content-Type: application/json" \ -d '{"path": "/data/papers/attention.pdf"}' # Schedule recurring index # Add to crontab or use built-in scheduler
markdown### Full-Text Search - Boolean queries: "attention mechanism" AND transformer - Phrase search: "self-attention" - Wildcard: transform* - Proximity: "attention transformer"~5 (within 5 words) - Field-specific: title:"attention" author:"Vaswani" ### Faceted Navigation - Filter by: author, date, organization, topic, language - Nested facets for hierarchical browsing - Date range slider - Entity type filters (person, organization, location) ### Semantic Features - Named entity highlighting in results - Related entity suggestions - Concept co-occurrence visualization - Auto-generated tag clouds
pythonimport requests SEARCH_URL = "http://localhost:8080/api/search" def search_papers(query, filters=None, max_results=20): """Search indexed documents.""" params = { "q": query, "rows": max_results, "fl": "title,author,content_type,date,score", "hl": "true", # Highlight matches "hl.fl": "content", # Highlight in content field "facet": "true", "facet.field": ["author", "organization", "topic"], } if filters: params["fq"] = filters resp = requests.get(SEARCH_URL, params=params) data = resp.json() results = data["response"]["docs"] facets = data.get("facet_counts", {}).get("facet_fields", {}) return results, facets # Search results, facets = search_papers( "attention mechanism transformer", filters='date:[2023-01-01T00:00:00Z TO *]', ) for doc in results: print(f"[{doc.get('date', 'N/A')}] {doc.get('title', 'Untitled')}") print(f" Score: {doc['score']:.2f}")
json{ "ner": { "engines": ["spacy", "stanford"], "models": { "spacy": "en_core_web_lg", "stanford": "english.all.3class.caseless" }, "entity_types": [ "PERSON", "ORG", "GPE", "DATE", "WORK_OF_ART", "EVENT" ], "custom_entities": { "METHODOLOGY": ["transformer", "CNN", "RNN", "GAN"], "DATASET": ["ImageNet", "CIFAR", "MNIST", "COCO"] } }, "classification": { "enabled": true, "model": "custom_topic_classifier", "categories": ["NLP", "CV", "RL", "Theory"] } }
python# Query the auto-built knowledge graph def get_entity_network(entity, depth=2): """Get co-occurring entities for a given entity.""" resp = requests.get( f"{SEARCH_URL}/graph", params={"entity": entity, "depth": depth}, ) graph = resp.json() for node in graph["nodes"]: print(f"Entity: {node['label']} ({node['type']})") for edge in graph["edges"]: print(f" {edge['source']} ↔ {edge['target']} " f"(co-occur: {edge['weight']})") get_entity_network("Transformer")
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-04 | fail→pass | 13,881 | 5,059 | -64% | 1 | 1 | 0% | 2,045 | 2,371 | +16% | 0 | 0 | — |
case-05 | fail→fail | 17,772 | 15,799 | -11% | 1 | 1 | 0% | 3,096 | 4,284 | +38% | 0 | 0 | — |
case-01 | fail→pass | 12,124 | 4,466 | -63% | 1 | 1 | 0% | 1,886 | 2,068 | +10% | 0 | 0 | — |
case-02 | fail→pass | 17,140 | 21,882 | +28% | 1 | 1 | 0% | 3,535 | 5,147 | +46% | 0 | 0 | — |
case-03 | fail→pass | 19,362 | 20,271 | +5% | 1 | 1 | 0% | 3,220 | 4,891 | +52% | 0 | 0 | — |
case-06 | fail→pass | 8,918 | 4,922 | -45% | 1 | 1 | 0% | 1,598 | 2,158 | +35% | 0 | 0 | — |
case-07 | fail→pass | 5,876 | 2,362 | -60% | 1 | 1 | 0% | 1,268 | 1,832 | +44% | 0 | 0 | — |
case-08 | fail→pass | 9,609 | 2,094 | -78% | 1 | 1 | 0% | 1,688 | 1,843 | +9% | 0 | 0 | — |
case-09 | pass→pass | 10,220 | 5,511 | -46% | 1 | 1 | 0% | 1,639 | 2,377 | +45% | 0 | 0 | — |
case-14 | pass→pass | 4,706 | 3,184 | -32% | 1 | 1 | 0% | 620 | 1,852 | +199% | 0 | 0 | — |
case-10 | fail→pass | 6,944 | 3,479 | -50% | 1 | 1 | 0% | 1,211 | 2,023 | +67% | 0 | 0 | — |
case-11 | pass→pass | 6,912 | 4,129 | -40% | 1 | 1 | 0% | 1,254 | 2,133 | +70% | 0 | 0 | — |
case-12 | fail→pass | 6,540 | 1,514 | -77% | 1 | 1 | 0% | 885 | 1,682 | +90% | 0 | 0 | — |
case-13 | fail→pass | 10,666 | 2,213 | -79% | 1 | 1 | 0% | 1,957 | 1,733 | -11% | 0 | 0 | — |
case-15 | pass→pass | 3,790 | 3,074 | -19% | 1 | 1 | 0% | 456 | 1,834 | +302% | 0 | 0 | — |
case-16 | pass→pass | 10,654 | 3,477 | -67% | 1 | 1 | 0% | 1,504 | 2,105 | +40% | 0 | 0 | — |
case-17 | fail→pass | 12,272 | 2,727 | -78% | 1 | 1 | 0% | 1,852 | 1,917 | +4% | 0 | 0 | — |
case-18 | pass→pass | 5,649 | 3,163 | -44% | 1 | 1 | 0% | 880 | 1,913 | +117% | 0 | 0 | — |
case-19 | pass→pass | 15,579 | 4,918 | -68% | 1 | 1 | 0% | 2,170 | 2,088 | -4% | 0 | 0 | — |
case-20 | fail→pass | 14,205 | 11,238 | -21% | 1 | 1 | 0% | 2,484 | 3,496 | +41% | 0 | 0 | — |
case-21 | fail→fail | 25,598 | 16,723 | -35% | 1 | 1 | 0% | 4,286 | 5,076 | +18% | 0 | 0 | — |
case-22 | fail→fail | 20,864 | 17,681 | -15% | 1 | 1 | 0% | 3,501 | 4,930 | +41% | 0 | 0 | — |
case-23 | fail→fail | 21,902 | 24,042 | +10% | 1 | 1 | 0% | 4,009 | 5,964 | +49% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +52 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.