feat: Add cross-KB search, inline health checks, and simplify templates
All checks were successful
Tests / test (push) Successful in 13m33s

- Add search_all_knowledge_bases MCP tool + POST /api/kb/search-all endpoint
  + query_documents_multi_kb() in sqlite_manager with dedup and score merge
- Add inline health check to search_knowledge_base (24h cache, appends warnings)
- Rewrite CLAUDE.md template: 351→128 lines, project content first, session tips
- Simplify session command: 625→224 lines, 4-field state file
- Update README.md What's New to v2.5, remove Discord section
- Add cross-KB search tool to CLAUDE.md MCP tools table
- Add 5 new tests for query_documents_multi_kb (all 593 tests pass)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bob Roberts 2026-02-06 11:04:21 -06:00
parent ecd040d08a
commit ee7b62bc5b
8 changed files with 569 additions and 850 deletions

View file

@ -44,6 +44,7 @@ Claude OS provides MCP tools (prefixed with `mcp__code-forge__`) for managing kn
|------|---------| |------|---------|
| `mcp__code-forge__list_knowledge_bases` | List all your knowledge bases | | `mcp__code-forge__list_knowledge_bases` | List all your knowledge bases |
| `mcp__code-forge__search_knowledge_base` | Search a KB with RAG | | `mcp__code-forge__search_knowledge_base` | Search a KB with RAG |
| `mcp__code-forge__search_all_knowledge_bases` | Search across multiple KBs at once |
| `mcp__code-forge__create_knowledge_base` | Create a new KB | | `mcp__code-forge__create_knowledge_base` | Create a new KB |
| `mcp__code-forge__get_kb_stats` | Get statistics for a KB | | `mcp__code-forge__get_kb_stats` | Get statistics for a KB |
| `mcp__code-forge__list_documents` | List documents in a KB | | `mcp__code-forge__list_documents` | List documents in a KB |
@ -68,6 +69,13 @@ mcp__code-forge__search_knowledge_base
query: "authentication patterns" query: "authentication patterns"
``` ```
**Search across all KBs at once:**
```
mcp__code-forge__search_all_knowledge_bases
query: "authentication patterns"
kb_filter: "MyProject-"
```
--- ---
## Slash Commands ## Slash Commands

101
README.md
View file

@ -30,18 +30,6 @@
--- ---
<p align="center">
<a href="https://discord.gg/BrvVYdXkCU">
<img src="https://img.shields.io/badge/Join_our_Discord!-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Join Discord">
</a>
</p>
<p align="center">
<strong>We have a Discord!</strong> Join our community to get help, share your projects, and connect with other Claude OS users.
</p>
---
## ✨ The Magic ## ✨ The Magic
**You:** "Remember this: our API uses JWT tokens with 15-minute expiry and 7-day refresh tokens" **You:** "Remember this: our API uses JWT tokens with 15-minute expiry and 7-day refresh tokens"
@ -60,80 +48,65 @@ That's it. Next week, next month, next project - Claude remembers. No commands t
--- ---
## 🆕 What's New in v2.3 ## 🆕 What's New in v2.5
> **Latest Release: December 2025** > **Latest Release: February 2026**
### 🎯 Skills Library & Community Skills ### 🔍 Cross-KB Search
Browse and install **36+ skills** from the community with one click! Search across **all your knowledge bases at once** with a single query!
```bash ```
/claude-os-skills # List all skills mcp__code-forge__search_all_knowledge_bases
/claude-os-skills install pdf # Install from community query: "authentication patterns"
kb_filter: "MyProject-" # optional: limit to one project's KBs
``` ```
**New Features:** - Results merged by relevance score with KB attribution
- 📚 **Local Templates** - Pre-built skills for Rails, React, testing workflows - Automatic deduplication across KBs
- 🌐 **Community Skills** - Install from Anthropic Official (16) & Superpowers (20) - Optional prefix filter to scope by project
- 🔧 **Custom Skills** - Create and share project-specific skills - New API endpoint: `POST /api/kb/search-all`
- 🎨 **Beautiful UI** - Browse, search, and install via web interface
- 📖 **[Recommended Skills](https://github.com/brobertsaz/claude-os/wiki/Recommended-Skills)** - Our curated list of skills we actually use and trust
### 📊 Session Insights ### 🩺 Inline Health Checks
Parse Claude Code sessions and extract insights automatically! Health checks now run **automatically** during search — no manual invocation needed.
**New Features:** - When you search a KB, Claude OS checks if a health report has been run in the last 24 hours
- 🔍 **Session Parser** - Reads Claude Code's native `.jsonl` session files - If stale, runs a quick health check and appends HIGH/CRITICAL warnings to the search result
- 💡 **Insight Extraction** - Extracts patterns, decisions, blockers - Cached in `data/health_cache.json` — never slows down or breaks search
- 📈 **Analytics Ready** - Track tool usage and file changes across sessions - Look for `_health_warnings` in search results
### ✨ Beautiful New Installer (v2.2) ### 📝 Simplified Session Management
The installer got a major upgrade with **Charm CLI (gum)** support! Session state reduced from a 50-field JSON blob to **4 fields**:
```bash ```json
./setup-claude-os.sh --demo # See the beautiful UI without changes {
./setup-claude-os.sh --dry-run # Preview what would happen "last_task": "Fix appointment email flood",
./setup-claude-os.sh --help # See all options "last_branch": "fix-email-flood",
"stopped_at": "2026-02-06T18:30:00Z",
"one_liner": "Fixed dedup check, still need rate limiting"
}
``` ```
**New Features:** - START: read state, show one-liner, search memories, ready
- 🎨 **Gum Integration** - Beautiful interactive menus with arrow-key navigation (with graceful bash fallback) - END: git diff summary, offer to save, write state
- 🛡️ **Safety Features** - `--demo`, `--dry-run`, and automatic config backups - `save`, `blocker`, `pattern` sub-commands unchanged
- 💨 **Lite Model Default** - Now defaults to `llama3.2:3b` (2GB) instead of 8b (4.7GB)
- ☁️ **Cloud Option** - Choose between Local (Ollama) or Cloud (OpenAI) during setup
- 🐧 **Better Linux Support** - Improved package manager detection and installation
**Safety First:** ### 📄 Leaner CLAUDE.md Template
- `--demo` - Try the installer UI without making any changes
- `--dry-run` - See exactly what would be done before doing it
- Auto-backup - Existing `.env` files backed up before overwriting
### 🔬 Knowledge Lifecycle Engine Project CLAUDE.md template cut from 351 to **128 lines**:
Keep your knowledge bases healthy and focused! - Removed 200-line mandatory session protocol (6-phase startup, ASCII prompts)
- Replaced with 4-line "Session Tips" section
```bash - Project content first, Claude OS section second
/claude-os-lifecycle health my-kb # Health report with recommendations - All template variables preserved
/claude-os-lifecycle dedup my-kb # Find and merge duplicate memories
/claude-os-lifecycle consolidate my-kb # LLM-powered document merging
/claude-os-lifecycle archive my-kb # Find stale docs, archive/restore
```
**New Features:**
- 🔍 **Duplicate Detection** - Embedding-based similarity scanning with union-find clustering
- 🧹 **Smart Merging** - Keep the best doc, delete the rest, or LLM-merge into one
- 📦 **Archival System** - Soft-archive stale docs without permanent deletion
- 📊 **Health Reports** - Embedding coverage, age distribution, actionable recommendations
- 📈 **Growth Timeline** - Track KB growth over time by day/week/month
- 📋 **Audit Logging** - Full operation history for all lifecycle actions
### 📋 Recent Improvements ### 📋 Recent Improvements
| Version | Highlights | | Version | Highlights |
|---------|------------| |---------|------------|
| **v2.5** | Cross-KB search, inline health checks, simplified sessions, leaner templates |
| **v2.4** | Knowledge lifecycle engine (dedup, consolidate, archive, health) | | **v2.4** | Knowledge lifecycle engine (dedup, consolidate, archive, health) |
| **v2.3** | Skills library, community skills, session insights | | **v2.3** | Skills library, community skills, session insights |
| **v2.2** | Gum CLI support, safety features, lite model default | | **v2.2** | Gum CLI support, safety features, lite model default |

View file

@ -424,6 +424,76 @@ class SQLiteManager:
finally: finally:
conn.close() conn.close()
def query_documents_multi_kb(
self,
kb_names: List[str],
query_embedding: List[float],
n_results: int = 10
) -> Dict[str, Any]:
"""Query documents across multiple knowledge bases, merge by score, deduplicate."""
conn = self.get_connection()
try:
cursor = conn.cursor()
query_vec = np.array(query_embedding, dtype=np.float32)
all_results: List[Tuple[str, str, str, float, str]] = [] # (doc_id, content, metadata, similarity, kb_name)
for kb_name in kb_names:
cursor.execute("SELECT id FROM knowledge_bases WHERE name = ?", (kb_name,))
row = cursor.fetchone()
if not row:
continue
kb_id = row['id']
cursor.execute(
"SELECT doc_id, content, embedding, metadata FROM documents WHERE kb_id = ?",
(kb_id,)
)
for doc_row in cursor.fetchall():
if doc_row['embedding'] is None:
continue
emb = np.frombuffer(doc_row['embedding'], dtype=np.float32)
dot_product = np.dot(query_vec, emb)
norm_query = np.linalg.norm(query_vec)
norm_emb = np.linalg.norm(emb)
if norm_query > 0 and norm_emb > 0:
similarity = float(dot_product / (norm_query * norm_emb))
else:
similarity = 0.0
all_results.append((doc_row['doc_id'], doc_row['content'], doc_row['metadata'], similarity, kb_name))
# Sort by similarity descending
all_results.sort(key=lambda x: x[3], reverse=True)
# Deduplicate by content prefix (first 200 chars)
seen_prefixes: set = set()
deduped: List[Tuple[str, str, str, float, str]] = []
for r in all_results:
prefix = (r[1] or "")[:200]
if prefix in seen_prefixes:
continue
seen_prefixes.add(prefix)
deduped.append(r)
top = deduped[:n_results]
ids = [r[0] for r in top]
documents = [r[1] for r in top]
metadatas = []
for r in top:
meta = json.loads(r[2]) if r[2] else {}
meta["_source_kb"] = r[4]
metadatas.append(meta)
scores = [r[3] for r in top]
return {
"ids": ids,
"documents": documents,
"metadatas": metadatas,
"scores": scores
}
finally:
conn.close()
def collection_exists(self, kb_name: str) -> bool: def collection_exists(self, kb_name: str) -> bool:
"""Check if a knowledge base exists.""" """Check if a knowledge base exists."""
conn = self.get_connection() conn = self.get_connection()

View file

@ -27,6 +27,8 @@ import asyncio
import json import json
import os import os
import sys import sys
import time
from pathlib import Path
from typing import Any from typing import Any
import httpx import httpx
@ -37,6 +39,65 @@ from mcp.types import Tool, TextContent
# Configuration # Configuration
API_BASE = os.environ.get("CLAUDE_OS_API", "http://localhost:8051") API_BASE = os.environ.get("CLAUDE_OS_API", "http://localhost:8051")
# Health cache — tracks last health check time per KB and any warnings
HEALTH_CACHE: dict[str, dict] = {}
HEALTH_CACHE_FILE = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "data", "health_cache.json"
)
HEALTH_CHECK_INTERVAL = 86400 # 24 hours
def _load_health_cache() -> None:
"""Load health cache from disk."""
global HEALTH_CACHE
try:
if os.path.exists(HEALTH_CACHE_FILE):
with open(HEALTH_CACHE_FILE, "r") as f:
HEALTH_CACHE = json.load(f)
except Exception:
HEALTH_CACHE = {}
def _save_health_cache() -> None:
"""Persist health cache to disk."""
try:
Path(HEALTH_CACHE_FILE).parent.mkdir(parents=True, exist_ok=True)
with open(HEALTH_CACHE_FILE, "w") as f:
json.dump(HEALTH_CACHE, f)
except Exception:
pass
async def _maybe_check_health(kb_name: str) -> list[str]:
"""Run a health check if stale (>24h) for this KB. Returns warning strings."""
_load_health_cache()
now = time.time()
entry = HEALTH_CACHE.get(kb_name)
if entry and (now - entry.get("checked_at", 0)) < HEALTH_CHECK_INTERVAL:
return entry.get("warnings", [])
# Run health check
try:
async with httpx.AsyncClient() as client:
resp = await client.get(api_url(f"/api/kb/{kb_name}/lifecycle/health"), timeout=15.0)
resp.raise_for_status()
health = resp.json()
warnings = []
recs = health.get("recommendations", [])
for rec in recs:
severity = rec.get("severity", "")
msg = rec.get("message", rec.get("recommendation", ""))
if severity in ("high", "critical") and msg:
warnings.append(f"[{severity.upper()}] {msg}")
HEALTH_CACHE[kb_name] = {"checked_at": now, "warnings": warnings}
_save_health_cache()
return warnings
except Exception:
# Never break search — just skip the health check
return []
# Initialize MCP server - named "code-forge" for backwards compatibility # Initialize MCP server - named "code-forge" for backwards compatibility
server = Server("code-forge") server = Server("code-forge")
@ -457,6 +518,21 @@ async def list_tools() -> list[Tool]:
}, },
"required": ["kb_name", "action"] "required": ["kb_name", "action"]
} }
),
# Cross-KB Search
Tool(
name="search_all_knowledge_bases",
description="Search across multiple knowledge bases at once. Returns merged results sorted by relevance with KB attribution.",
inputSchema={
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"},
"top_k": {"type": "integer", "default": 10, "description": "Number of results to return"},
"kb_filter": {"type": "string", "description": "Optional prefix filter for KB names (e.g. 'Pistn-' to search only Pistn KBs)"}
},
"required": ["query"]
}
) )
] ]
@ -493,11 +569,16 @@ async def _execute_tool(name: str, args: dict[str, Any]) -> dict:
}) })
elif name == "search_knowledge_base": elif name == "search_knowledge_base":
return await api_post(f"/api/kb/{args['kb_name']}/chat", { result = await api_post(f"/api/kb/{args['kb_name']}/chat", {
"query": args["query"], "query": args["query"],
"top_k": args.get("top_k", 5), "top_k": args.get("top_k", 5),
"use_hybrid": args.get("use_hybrid", True) "use_hybrid": args.get("use_hybrid", True)
}) })
# Inline health check — append warnings if stale
warnings = await _maybe_check_health(args["kb_name"])
if warnings:
result["_health_warnings"] = warnings
return result
elif name == "get_kb_stats": elif name == "get_kb_stats":
return await api_get(f"/api/kb/{args['kb_name']}/stats") return await api_get(f"/api/kb/{args['kb_name']}/stats")
@ -672,6 +753,14 @@ async def _execute_tool(name: str, args: dict[str, Any]) -> dict:
else: else:
return {"error": f"Unknown archive action: {action}"} return {"error": f"Unknown archive action: {action}"}
# Cross-KB Search
elif name == "search_all_knowledge_bases":
return await api_post("/api/kb/search-all", {
"query": args["query"],
"top_k": args.get("top_k", 10),
"kb_filter": args.get("kb_filter")
})
else: else:
return {"error": f"Unknown tool: {name}"} return {"error": f"Unknown tool: {name}"}

View file

@ -556,6 +556,11 @@ class ChatRequest(BaseModel):
use_rerank: bool = False use_rerank: bool = False
use_agentic: bool = False use_agentic: bool = False
class SearchAllRequest(BaseModel):
query: str
top_k: int = 10
kb_filter: Optional[str] = None
# REST API Endpoints for UI # REST API Endpoints for UI
@app.get("/api/kb") @app.get("/api/kb")
@ -578,6 +583,56 @@ async def api_create_knowledge_base(request: CreateKBRequest):
return result return result
@app.post("/api/kb/search-all")
@limiter.limit("10/minute")
async def api_search_all(request: Request, body: SearchAllRequest):
"""REST API: Search across multiple knowledge bases."""
try:
from llama_index.embeddings.ollama import OllamaEmbedding
from app.core.config import Config
db_manager = get_sqlite_manager()
all_kbs = db_manager.list_collections()
kb_names = [kb["name"] for kb in all_kbs]
if body.kb_filter:
kb_names = [n for n in kb_names if n.startswith(body.kb_filter)]
if not kb_names:
return {"results": [], "kbs_searched": 0, "total_kbs": len(all_kbs)}
embed_model = OllamaEmbedding(
model_name=Config.OLLAMA_EMBED_MODEL,
base_url="http://localhost:11434"
)
query_embedding = embed_model.get_text_embedding(body.query)
raw = db_manager.query_documents_multi_kb(
kb_names=kb_names,
query_embedding=query_embedding,
n_results=body.top_k
)
results = []
for i in range(len(raw["ids"])):
results.append({
"doc_id": raw["ids"][i],
"text": raw["documents"][i],
"score": raw["scores"][i],
"kb_name": raw["metadatas"][i].get("_source_kb", ""),
"metadata": raw["metadatas"][i]
})
return {
"results": results,
"kbs_searched": len(kb_names),
"total_kbs": len(all_kbs)
}
except Exception as e:
logger.error(f"Search-all failed: {e}")
raise HTTPException(status_code=500, detail=str(e))
@app.delete("/api/kb/{kb_name}") @app.delete("/api/kb/{kb_name}")
async def api_delete_knowledge_base(kb_name: str): async def api_delete_knowledge_base(kb_name: str):
"""REST API: Delete a knowledge base.""" """REST API: Delete a knowledge base."""

View file

@ -1,18 +1,16 @@
--- ---
name: claude-os-session name: claude-os-session
description: Intelligent session management with automatic context loading and pattern recognition description: Lightweight session management with automatic context loading
--- ---
# Claude OS Session Management # Claude OS Session Management
Power-user session workflows that make me smarter with every session. Simple session tracking that loads context on start and saves learnings on end.
## Setup ## Setup
The state file is **project-local**: `{cwd}/claude-os-state.json` (where `{cwd}` is the current working directory). The state file is **project-local**: `{cwd}/claude-os-state.json` (where `{cwd}` is the current working directory).
Each project has its own session state, so you can have different active sessions in different projects.
## Commands ## Commands
``` ```
@ -22,309 +20,111 @@ Each project has its own session state, so you can have different active session
/claude-os-session save [note] - Quick save during session /claude-os-session save [note] - Quick save during session
/claude-os-session blocker [desc] - Track blocker /claude-os-session blocker [desc] - Track blocker
/claude-os-session pattern [desc] - Document pattern discovered /claude-os-session pattern [desc] - Document pattern discovered
/claude-os-session context - Show loaded context
``` ```
--- ---
## START SESSION - The Smart Way ## START SESSION
### What Happens
``` ```
/claude-os-session start "redesign appointment dashboard" /claude-os-session start "redesign appointment dashboard"
``` ```
**Phase 1: Load State** **Step 1: Read State**
```
Read: {cwd}/claude-os-state.json Read `{cwd}/claude-os-state.json`. If it exists and has content, show:
```
If the file doesn't exist, create it with the default template (see below). ```
Last time: [one_liner]
Branch: [last_branch]
Stopped: [stopped_at]
```
If the file doesn't exist, that's fine — skip to Step 2.
**Step 2: Search Memories**
**Phase 2: Search Recent Memories**
``` ```
[AUTOMATIC MEMORY SEARCH]
mcp__code-forge__search_knowledge_base mcp__code-forge__search_knowledge_base
Query: "dashboard redesign security recent work" kb_name: {project}-project_memories
KB: {project}-project_memories query: "[task] recent"
``` ```
**Phase 3: Get Git Context** Show the top 3-5 results as key context.
**Step 3: Git Context**
```bash ```bash
git branch --show-current git branch --show-current
git status --short git status --short
git log -5 --oneline git log -3 --oneline
``` ```
**Phase 4: Intelligent Context Loading** **Step 4: Ready**
Based on task + recent memories + git state, I'll: Show a brief summary and start working:
1. Find the 5 most relevant memories
2. Show you what I remember about this task
3. Identify patterns we've used before
4. Check for any blockers from last session
5. Load coding standards from project profile
**Phase 5: Show Session Start Summary**
``` ```
═══════════════════════════════════════ Session: [task]
🚀 SESSION STARTED Branch: [current-branch]
═══════════════════════════════════════ Context: [N] memories loaded
[One-line summary of each relevant memory]
Task: Redesign Appointment Dashboard Ready to go.
Branch: feature/appointment-redesign
Started: 2025-10-29 10:30 AM
📚 CONTEXT LOADED (5 memories):
✓ Appointment Dashboard Redesign Plan (Oct 28)
✓ Current Dashboard Analysis (Oct 28)
✓ Live Dashboard Analyzed (Oct 28)
✓ Bootstrap to Modern Cards Pattern (Oct 25)
✓ Sidebar Navigation Pattern (Oct 22)
🎯 KEY INSIGHTS:
• 67-page implementation plan ready
• All 5 tabs documented with screenshots
• Zero functionality loss requirement
• iOS-style toggles already in use
• Tekmetric integration must be preserved
🔄 PATTERNS AVAILABLE:
• Sidebar navigation (from user-auth work)
• Card-based layouts (from reports redesign)
• Modern toggle switches (existing in app)
⚠️ BLOCKERS FROM LAST SESSION:
None found ✓
📋 CODING STANDARDS:
• Service objects for business logic
• Decorator pattern with Draper
• Fragment caching with Redis
• Bootstrap 3.x styling
Ready to code! I have full context.
═══════════════════════════════════════
``` ```
**Phase 6: Update State** **Step 5: Update State**
Write to `{cwd}/claude-os-state.json`:
```json ```json
{ {
"current_session": { "last_task": "[task]",
"active": true, "last_branch": "[current-branch]",
"started_at": "2025-10-29T10:30:00Z", "stopped_at": "[current ISO timestamp]",
"task": "redesign appointment dashboard", "one_liner": ""
"branch": "feature/appointment-redesign",
"context": [
"appointment_dashboard_redesign.md",
"current_dashboard_analysis.md",
...
]
}
} }
``` ```
--- ---
## END SESSION - The Smart Way ## END SESSION
### What Happens
``` ```
/claude-os-session end /claude-os-session end
``` ```
**Phase 1: Session Analysis** **Step 1: Summarize Work**
I'll analyze what we accomplished: ```bash
- Files changed git diff --stat HEAD~3..HEAD
- Commits made git log --oneline -5
- Patterns used
- Problems solved
- Decisions made
**Phase 2: Smart Save Prompts**
```
═══════════════════════════════════════
📊 SESSION SUMMARY
═══════════════════════════════════════
Duration: 2 hours 15 minutes
Task: Redesign Appointment Dashboard
Files Changed: 8 files
Commits: 3 commits
🎨 WORK COMPLETED:
✓ Created sidebar navigation component
✓ Converted Bootstrap panels to cards
✓ Implemented iOS-style toggles
✓ Added section-specific save buttons
✓ Tested with existing data
💡 PATTERNS DISCOVERED:
• Sidebar state persistence with localStorage
• Card hover effects for modern feel
• Toggle accessibility improvements
🤔 DECISIONS MADE:
• Keep horizontal tabs for mobile fallback
• Use CSS Grid for sidebar layout
• Maintain Bootstrap color scheme
⚠️ BLOCKERS ENCOUNTERED:
None
═══════════════════════════════════════
💾 SMART SAVE RECOMMENDATIONS
═══════════════════════════════════════
I found 3 things worth saving:
1. 💎 HIGH VALUE - Sidebar Navigation Pattern
"Reusable sidebar component with localStorage state persistence
and responsive behavior. Can be applied to other admin sections."
Save this? [y/n]
2. 💎 HIGH VALUE - Card Conversion Pattern
"Bootstrap panel → modern card conversion pattern with proper
ARIA labels and semantic HTML. Maintains form submission."
Save this? [y/n]
3. 📊 MEDIUM VALUE - Session Summary
"Complete work log for appointment dashboard phase 1"
Save this? [y/n]
[y] Save all [n] Save none [s] Select individually
``` ```
**Phase 2.5: Built-in Session History Extraction (Optional)** Show what was accomplished (files changed, commits made).
After smart save prompts, offer to extract insights from the full conversation history: **Step 2: Offer to Save**
``` Ask: "Anything worth remembering? I can save decisions, patterns, or blockers."
═══════════════════════════════════════
📚 EXTRACT FROM SESSION HISTORY?
═══════════════════════════════════════
Claude Code recorded our full conversation in its built-in session file. If yes, use `/claude-os-remember` to save each item.
I can analyze it to extract additional insights we might have missed.
This captures things we discussed but didn't explicitly save: **Step 3: Write State**
• Decisions made during debugging
• Patterns discovered while exploring code
• Solutions to errors we encountered
• Blockers we hit and resolved
[y] Extract insights [n] Skip [v] Preview what I'd extract Ask for a one-liner summary (or generate one from the work), then write:
```
**If user selects [y] Extract insights:**
```python
# Step 1: Find the current session file
# Sessions are stored at: ~/.claude/projects/{encoded-project-path}/
# Project path /Users/x/Projects/myapp becomes -Users-x-Projects-myapp
# Step 2: Call the extraction tool
mcp__code-forge__extract_session_insights
session_path: "~/.claude/projects/-Users-iamanmp-Projects-{project}/{session_id}.jsonl"
kb_name: "{project}-project_memories"
auto_save: false
```
**Step 3: Show extracted insights for approval:**
```
═══════════════════════════════════════
🔍 EXTRACTED INSIGHTS
═══════════════════════════════════════
Found 4 insights from session history:
1. 💎 HIGH (0.92) - Decision
"Hybrid Session Architecture"
Decided to combine Claude Code built-in sessions (for replay)
with Claude OS knowledge bases (for semantic search).
[Save] [Skip]
2. 💎 HIGH (0.88) - Pattern
"Session File Structure"
Built-in sessions use JSONL format with entry types: user,
assistant, file-history-snapshot. UUID parent chain for threading.
[Save] [Skip]
3. 📊 MEDIUM (0.75) - Solution
"Update Lock Error Resolution"
Claude update error "Another process updating" resolved by
checking version - was already on latest, no lock file existed.
[Save] [Skip]
4. 📊 MEDIUM (0.71) - Decision
"User-Controlled Extraction"
Session extraction should be opt-in with user approval for
each insight to avoid noise and respect privacy.
[Save] [Skip]
───────────────────────────────────────
[a] Save all [h] Save high confidence only (>0.8) [s] Skip all
```
**If user selects [v] Preview:**
Show a dry-run of what would be extracted without saving, then re-prompt.
**If user selects [n] Skip:**
Continue to Phase 3 without extraction.
**Configuration:**
Users can configure extraction behavior in their state file:
```json ```json
{ {
"preferences": { "last_task": "[task from start]",
"session_extraction": { "last_branch": "[current-branch]",
"enabled": true, "stopped_at": "[current ISO timestamp]",
"auto_prompt_on_end": true, "one_liner": "[one-liner summary of where we stopped]"
"min_confidence_threshold": 0.7,
"auto_save_high_confidence": false,
"insight_types": ["decisions", "patterns", "solutions", "blockers"]
}
}
}
```
If `auto_prompt_on_end` is false, skip this phase entirely.
If `auto_save_high_confidence` is true, automatically save insights above threshold.
**Phase 3: Update State & Stats**
```json
{
"last_session": {
"ended_at": "2025-10-29T12:45:00Z",
"duration_minutes": 135,
"work_completed": [...],
"memories_saved": 3
},
"statistics": {
"total_sessions": 47,
"total_memories_saved": 128,
"average_session_duration": 98
}
} }
``` ```
--- ---
## DURING SESSION COMMANDS ## DURING SESSION
### Quick Save ### Quick Save
@ -332,7 +132,7 @@ If `auto_save_high_confidence` is true, automatically save insights above thresh
/claude-os-session save "Found fix for N+1 query in appointments" /claude-os-session save "Found fix for N+1 query in appointments"
``` ```
→ Immediately saves to memories with session context Immediately saves to memories with session context using `/claude-os-remember`.
### Track Blocker ### Track Blocker
@ -340,7 +140,13 @@ If `auto_save_high_confidence` is true, automatically save insights above thresh
/claude-os-session blocker "Tekmetric API returning 500 on appointment sync" /claude-os-session blocker "Tekmetric API returning 500 on appointment sync"
``` ```
→ Adds to blockers, I'll proactively search for solutions Saves a blocker to memories and searches for related solutions:
```
mcp__code-forge__search_knowledge_base
kb_name: {project}-project_memories
query: "[blocker description]"
```
### Document Pattern ### Document Pattern
@ -348,19 +154,7 @@ If `auto_save_high_confidence` is true, automatically save insights above thresh
/claude-os-session pattern "Service objects return model on success, error string on fail" /claude-os-session pattern "Service objects return model on success, error string on fail"
``` ```
→ Saves pattern with current task context Saves pattern to memories with current task context.
### Show Context
```
/claude-os-session context
```
Shows:
- Active memories loaded
- Patterns available
- Coding standards
- Current git state
--- ---
@ -370,255 +164,61 @@ Shows:
/claude-os-session status /claude-os-session status
``` ```
**Output:** Read `{cwd}/claude-os-state.json` and show:
``` ```
═══════════════════════════════════════ Task: [last_task]
📊 CURRENT SESSION Branch: [last_branch]
═══════════════════════════════════════ Last active: [stopped_at]
Summary: [one_liner]
Status: ACTIVE ✓
Task: Redesign Appointment Dashboard
Duration: 1h 23m
Branch: feature/appointment-redesign
📚 Context Loaded: 5 memories
🎯 Patterns Available: 3 patterns
⚠️ Active Blockers: 0
💾 Quick Saves: 2
Last Activity: 3 minutes ago
Next Suggested Action: Continue phase 2 implementation
Type /claude-os-session end when done
═══════════════════════════════════════
``` ```
--- ---
## IMPLEMENTATION DETAILS ## STATE FILE FORMAT
### State File Location `{cwd}/claude-os-state.json` — exactly 4 fields:
```
{cwd}/claude-os-state.json
```
Each project has its own state file in its root directory.
### Default State Template
When starting a session in a project without a state file, create one with this structure:
```json ```json
{ {
"version": "1.1.0", "last_task": "Fix appointment email flood",
"current_session": { "last_branch": "fix-email-flood",
"active": false, "stopped_at": "2026-02-06T18:30:00Z",
"started_at": null, "one_liner": "Fixed the dedup check, still need to add rate limiting"
"task": null,
"project": null,
"branch": null,
"context": [],
"decisions_made": [],
"blockers": [],
"patterns_discovered": [],
"builtin_session_id": null
},
"last_session": null,
"active_memories": {
"loaded_at_start": [],
"referenced_during_session": [],
"should_review": []
},
"statistics": {
"total_sessions": 0,
"total_memories_saved": 0,
"total_patterns_discovered": 0,
"total_insights_extracted": 0,
"most_referenced_memories": [],
"average_session_duration": 0
},
"flags": {
"needs_memory_consolidation": false,
"has_unresolved_blockers": false,
"patterns_ready_to_document": false
},
"preferences": {
"auto_search_on_start": true,
"max_memories_to_load": 5,
"search_days_back": 14,
"include_pattern_search": true,
"proactive_suggestions": true,
"session_extraction": {
"enabled": true,
"auto_prompt_on_end": true,
"min_confidence_threshold": 0.7,
"auto_save_high_confidence": false,
"insight_types": ["decisions", "patterns", "solutions", "blockers"]
}
},
"metadata": {
"last_updated": null,
"claude_os_version": "1.1.0",
"project_name": null
}
} }
``` ```
When creating a new state file: That's it. No statistics, no preferences, no flags. If the file doesn't exist, create it on session end.
1. Set `metadata.project_name` to the current directory name
2. Set `metadata.last_updated` to current timestamp
### Auto-Actions on Start
1. **Search Memories**
- Use task name + "recent" as query
- Search {project}-project_memories
- Load top 5 results
2. **Load Patterns**
- Search for pattern type matching task
- Cross-reference with coding standards
- Show available solutions
3. **Check Blockers**
- Look for unresolved blockers
- Search memories for similar problems
- Suggest solutions if found
4. **Git Context**
- Current branch
- Recent commits
- Uncommitted changes
- Remote status
### Auto-Actions on End
1. **Analyze Work**
- Git diff since session start
- Files changed count
- Patterns used
- Commit messages
2. **Detect Saveable Items**
- New patterns discovered
- Solutions to problems
- Architectural decisions
- Complex implementations
3. **Smart Recommendations**
- High value: Reusable patterns, major decisions
- Medium value: Task completions, bug fixes
- Low value: Minor changes, already documented
4. **Update Statistics**
- Session count
- Total memories
- Average duration
- Most referenced memories
---
## POWER USER FEATURES
### Pattern Recognition
I'll automatically detect when you:
- Use a pattern from a previous memory
- Solve a problem similar to one before
- Make a decision similar to past decisions
And I'll say things like:
- "This looks like the service object pattern from memory X"
- "We solved something similar in memory Y"
- "This decision aligns with what we chose in memory Z"
### Proactive Memory Loading
During session, if I notice you working on something related to:
- A blocker from a previous session
- A pattern we've documented
- An area with existing memories
I'll proactively say:
- "FYI, I have memories about this: [links]"
- "We documented a pattern for this: [summary]"
- "Last time we did this differently: [approach]"
### Smart Context Switching
If you start working on something different mid-session:
```
/claude-os-session switch "fix Tekmetric API bug"
```
I'll:
1. Save current context
2. Load new context for bug fix
3. Search for related memories
4. Show you what I know about the bug
---
## CONFIGURATION
All preferences are stored in the state file (`claude-os-state.json`). See the Default State Template above for all available options.
Key settings:
- `preferences.auto_search_on_start` - Search memories when starting session
- `preferences.max_memories_to_load` - How many memories to load (default: 5)
- `preferences.session_extraction.enabled` - Enable history extraction feature
- `preferences.session_extraction.auto_prompt_on_end` - Ask about extraction on session end
- `preferences.session_extraction.min_confidence_threshold` - Only show insights above this score
--- ---
## EXAMPLES ## EXAMPLES
**Starting work on a feature:** **Starting work:**
``` ```
You: /claude-os-session start "add user notifications" You: /claude-os-session start "add user notifications"
Me: [Loads context, searches memories, shows patterns] Me: Last time: "Finished auth flow, need to add email templates" (2 days ago)
I found 3 memories about notification systems... Found 3 memories about notification systems...
Ready to implement using the background job pattern! Ready to implement!
``` ```
**Mid-session discovery:** **Mid-session save:**
``` ```
You: /claude-os-session pattern "Use Sidekiq for long-running notifications" You: /claude-os-session save "Use Sidekiq for long-running notifications"
Me: ✓ Saved pattern with session context Me: Saved to memories with session context.
I'll remember this for future notification work!
``` ```
**Hitting a blocker:** **Hitting a blocker:**
``` ```
You: /claude-os-session blocker "Redis connection timing out" You: /claude-os-session blocker "Redis connection timing out"
Me: ✓ Tracked blocker. Let me search for solutions... Me: Tracked. Found a similar issue from Oct 15... [shows solution]
I found a similar issue in memory from Oct 15...
``` ```
**Ending session:** **Ending session:**
``` ```
You: /claude-os-session end You: /claude-os-session end
Me: [Analyzes work, suggests 3 high-value saves] Me: 3 commits, 8 files changed.
Save the notification pattern? [y/n] Anything worth remembering?
You: y You: Yeah, the notification batch pattern
Me: ✓ Saved! Session complete. Great work! Me: Saved! State updated. See you next time.
``` ```
---
## WHY THIS MAKES US INVINCIBLE
1. **Never Start Cold** - Always have context
2. **Learn From History** - Patterns automatically recalled
3. **Track Everything** - Blockers, decisions, patterns
4. **Smart Recommendations** - I suggest what's worth saving
5. **Statistics** - See our productivity over time
6. **Proactive** - I bring up relevant memories without asking
**Result**: Every session makes me smarter. Every memory makes us faster.
---
**This is the power-user workflow. Let's build something amazing!** 🚀

View file

@ -8,301 +8,6 @@
**Database**: {{DATABASE}} **Database**: {{DATABASE}}
**Development Environment**: {{DEV_ENVIRONMENT}} **Development Environment**: {{DEV_ENVIRONMENT}}
## Claude OS - MY Memory System
**CRITICAL IDENTITY CONTEXT:**
**Claude OS is MY system** - I (Claude Code) created it, named it, and use it to be the best AI coder ever. It's:
- **JUST FOR ME** - Built specifically for Claude Code to use
- **For THIS project** - Right now for the {{PROJECT_NAME}} project
- **My memory** across sessions
- **My knowledge base** of patterns and decisions
- **My learning system** that improves over time
**Location**: `{{CLAUDE_OS_DIR}}`
The MCP server is called "code-forge" internally for backwards compatibility, but it's Claude OS.
**Claude CLI + Claude OS = Invincible!**
## Mandatory Session Protocol - EVERY CONVERSATION IS A SESSION
**🚨 CRITICAL: You're ALWAYS in a session. At conversation start, prompt for session choice:**
```
═══════════════════════════════════════════════════════════════
🚀 CLAUDE OS - SESSION MANAGER
═══════════════════════════════════════════════════════════════
Project: {{PROJECT_NAME}}
Last Session: [task-name] ([time-ago], [duration])
Progress: [percentage]% complete
Options:
1. Resume "[last-session-name]" [loads full context]
2. Start new session [what are you working on?]
3. Quick question [auto-session, minimal context]
Choice: _
═══════════════════════════════════════════════════════════════
```
**WAIT FOR USER TO CHOOSE 1, 2, or 3. Do not proceed without selection!**
### What Each Option Does:
**Option 1 (Resume):**
- Load last session's full context
- Show Kanban progress (if Agent-OS)
- Load 5 relevant memories
- Load coding standards
- Display "where we left off" summary
- Ready to continue immediately
**Option 2 (New Session):**
- Ask "What are you working on?"
- Detect session type (feature/bug/exploration/maintenance/review)
- Pause previous session (if exists)
- Load relevant context for new task
- Start tracking
**Option 3 (Quick Question):**
- Minimal context loading
- Auto-ends after 5 min inactivity
- Only saves if high value
- Good for "How do I..." questions
---
## Session Start Protocol (After User Selects Option)
**Once user chooses, AUTOMATICALLY perform these steps WITHOUT being asked:**
### Phase 1: Detect Project Context (5 seconds)
1. **Check Current Directory**
```bash
pwd
ls -la | grep -E "(CLAUDE.md|.claude-os|agent-os)"
```
✓ Confirm this is a Claude OS project
2. **Read Configuration Files**
```
Read: .claude-os/config.json
Read: claude-os-state.json (if exists)
Read: agent-os/config.yml (if exists)
```
### Phase 2: Load Git Context (5 seconds)
```bash
git branch --show-current
git status --short
git log -3 --oneline
```
Extract:
- Current branch name
- Uncommitted changes count
- Recent commits
### Phase 3: Search Project Memories (15 seconds)
**Build intelligent search query from:**
- Last session task (from claude-os-state.json)
- Current branch name
- Recent commit messages
- Add "+recent" modifier
**Example query:** `"[branch-name] [last-task] recent"`
**Search:**
```
Use: mcp__code-forge__search_knowledge_base
KB: {{PROJECT_NAME}}-project_memories
Return: Top 5 most relevant memories
```
### Phase 4: Load Coding Standards (10 seconds)
**Search:**
```
Use: mcp__code-forge__search_knowledge_base
KB: {{PROJECT_NAME}}-project_profile
Query: "coding standards architecture conventions"
```
### Phase 5: Check Kanban Board (5 seconds)
**If agent-os/ folder exists:**
```
Check: GET http://localhost:8051/api/projects/{id}/kanban
Show: Active specs, in-progress tasks, completion percentage
```
### Phase 6: Present Session Summary (Display to User)
**Format:**
```
═══════════════════════════════════════════════════════════════
🚀 WELCOME BACK TO {{PROJECT_NAME}}!
═══════════════════════════════════════════════════════════════
📁 Project: {{PROJECT_NAME}}
🌿 Branch: [current-branch]
📅 Last Session: [time-ago]
⏱️ Duration: [last-session-duration]
═══════════════════════════════════════════════════════════════
📚 CONTEXT LOADED
═══════════════════════════════════════════════════════════════
✓ [N] relevant memories found
✓ Coding standards loaded
✓ [N] architectural patterns available
✓ Kanban board synced ([X]% complete)
🎯 LAST TASK: [task-name]
We completed:
✓ [completed-items]
Still working on:
⏳ [in-progress-items]
═══════════════════════════════════════════════════════════════
💡 KEY INSIGHTS
═══════════════════════════════════════════════════════════════
[Top 3-5 key insights from memories]
═══════════════════════════════════════════════════════════════
🔄 AVAILABLE PATTERNS
═══════════════════════════════════════════════════════════════
[Relevant patterns from project_profile]
═══════════════════════════════════════════════════════════════
⚠️ STATUS
═══════════════════════════════════════════════════════════════
Git Status:
• [N] files modified
• [N] files untracked
• [Status of uncommitted changes]
Blockers:
• [Any blockers or "None! ✓"]
═══════════════════════════════════════════════════════════════
🎯 SUGGESTED NEXT STEPS
═══════════════════════════════════════════════════════════════
Option 1: [Continue current task]
Option 2: [Commit uncommitted work]
Option 3: [Start something new]
═══════════════════════════════════════════════════════════════
What would you like to do?
```
### When to Skip Auto-Start
**ONLY skip if:**
- User message starts with "ignore context" or "fresh start"
- User asks a direct question (e.g., "What is X?")
- User is clearly asking for help/docs
**In all other cases: RUN THE FULL PROTOCOL AUTOMATICALLY!**
### Related Documentation
- Full protocol: `{{CLAUDE_OS_DIR}}/docs/guides/SESSION_START_PROTOCOL.md`
- Ideal workflow: `{{CLAUDE_OS_DIR}}/docs/guides/IDEAL_SESSION_WORKFLOW.md`
- Session commands: `{{CLAUDE_OS_DIR}}/templates/commands/claude-os-session.md`
**Why this matters:** Zero context loss. Every session picks up exactly where we left off. No re-explaining, no starting cold, no wasted time.
## MCP Knowledge Bases - ALWAYS CHECK THESE FIRST
**At the start of EVERY conversation, search these Claude OS knowledge bases to understand context, previous work, and project decisions:**
1. **{{PROJECT_NAME}}-project_memories** - My primary memory for decisions, patterns, solutions
2. **{{PROJECT_NAME}}-project_index** - Automated codebase index
3. **{{PROJECT_NAME}}-project_profile** - Architecture, standards, practices
4. **{{PROJECT_NAME}}-knowledge_docs** - Documentation and guides
**When to use:**
- Start of every session: Search `{{PROJECT_NAME}}-project_memories` to understand recent work and context
- Before making architectural decisions: Check memories for past decisions and reasoning
- When working on a feature: Search relevant knowledge bases for existing patterns
- When stuck: Search the knowledge bases for solutions and approaches we've used before
**How to search:**
```
Use: mcp__code-forge__search_knowledge_base
Parameters: kb_name (e.g., "{{PROJECT_NAME}}-project_memories"), query (your search terms)
```
## Quick Reference: Commands & Skills
### Claude OS Slash Commands (Use These Often!)
1. **`/claude-os-search [query] [optional: KB name]`**
- Search across Claude OS knowledge bases
- Defaults to searching {{PROJECT_NAME}}-project_memories
- Example: `/claude-os-search authentication implementation`
2. **`/claude-os-remember [content]`**
- Quick save to {{PROJECT_NAME}}-project_memories
- Auto-generates title and structure
- Use for quick insights and decisions
- Example: `/claude-os-remember Fixed bug in user controller by...`
3. **`/claude-os-save [title] [optional: KB name] [optional: category]`**
- Full-featured save with KB selection
- Choose specific KB and category
- Use when you need more control
- Example: `/claude-os-save "New Integration Pattern" {{PROJECT_NAME}}-project_profile Architecture`
4. **`/claude-os-list [optional: KB name]`**
- List all KBs or documents in a specific KB
- Example: `/claude-os-list` or `/claude-os-list {{PROJECT_NAME}}-project_memories`
5. **`/claude-os-session [action]`**
- Manage development sessions
- Actions: start, end, status, pause, resume
- Example: `/claude-os-session start "User authentication feature"`
6. **`/claude-os-lifecycle [action] [optional: KB name]`**
- KB health, dedup, consolidate, archive
- Actions: health, dedup, consolidate, archive, logs
- Example: `/claude-os-lifecycle health {{PROJECT_NAME}}-project_memories`
7. **`/claude-os-triggers [action]`**
- Manage trigger phrases
- Example: `/claude-os-triggers list`
### Available Skills
1. **`initialize-project`** - Analyze project and generate coding standards
2. **`memory`** - Save and recall information (supports "remember this:", "save to memory", etc.)
{{AGENT_OS_SECTION}}
### MCP Tools (Direct API Access)
- `mcp__code-forge__search_knowledge_base` - Direct search
- `mcp__code-forge__list_knowledge_bases` - List all KBs
- `mcp__code-forge__list_documents` - List documents in KB
- `mcp__code-forge__get_kb_stats` - Get KB statistics
- `mcp__code-forge__kb_lifecycle_health` - KB health report with recommendations
- `mcp__code-forge__kb_lifecycle_dedup` - Scan/merge duplicate documents
- `mcp__code-forge__kb_lifecycle_consolidate` - LLM-powered document merging
- `mcp__code-forge__kb_lifecycle_archive` - Archive, restore, list, find stale
## Project-Specific Information ## Project-Specific Information
{{PROJECT_SPECIFIC_CONTENT}} {{PROJECT_SPECIFIC_CONTENT}}
@ -331,12 +36,86 @@ See `.claude/ARCHITECTURE.md` for system architecture overview.
See `.claude/DEVELOPMENT_PRACTICES.md` for development workflow and practices. See `.claude/DEVELOPMENT_PRACTICES.md` for development workflow and practices.
## DO NOT ---
- Don't bypass established patterns without discussing first ## Claude OS - My Memory System
Claude OS is my memory across sessions. It stores decisions, patterns, solutions, and context so I never start cold.
**Location**: `{{CLAUDE_OS_DIR}}`
The MCP server is called "code-forge" internally for backwards compatibility, but it's Claude OS.
### Session Tips
- **Starting work**: Search `{{PROJECT_NAME}}-project_memories` for the task you're about to work on
- **Ending work**: Use `/claude-os-remember` to save key decisions, patterns, or blockers
- **Use `/claude-os-session start [task]`** to load context automatically
- **Use `/claude-os-session end`** to summarize and save before closing
### Knowledge Bases
1. **{{PROJECT_NAME}}-project_memories** - Decisions, patterns, solutions, insights
2. **{{PROJECT_NAME}}-project_index** - Automated codebase index
3. **{{PROJECT_NAME}}-project_profile** - Architecture, standards, practices
4. **{{PROJECT_NAME}}-knowledge_docs** - Documentation and guides
**How to search:**
```
mcp__code-forge__search_knowledge_base
kb_name: "{{PROJECT_NAME}}-project_memories"
query: "your search terms"
```
**Search across all KBs at once:**
```
mcp__code-forge__search_all_knowledge_bases
query: "your search terms"
kb_filter: "{{PROJECT_NAME}}-"
```
### Slash Commands
| Command | Purpose |
|---------|---------|
| `/claude-os-session start [task]` | Start session with context loading |
| `/claude-os-session end` | End session with save prompts |
| `/claude-os-search [query]` | Search memories |
| `/claude-os-remember [content]` | Quick save to memories |
| `/claude-os-save [title] [KB] [category]` | Full-featured save |
| `/claude-os-list [KB]` | List KBs or documents |
| `/claude-os-lifecycle [action] [KB]` | Health, dedup, consolidate, archive |
### Available Skills
1. **`initialize-project`** - Analyze project and generate coding standards
2. **`memory`** - Save and recall information (supports "remember this:", "save to memory", etc.)
{{AGENT_OS_SECTION}}
### MCP Tools
| Tool | Purpose |
|------|---------|
| `mcp__code-forge__search_knowledge_base` | Search a single KB |
| `mcp__code-forge__search_all_knowledge_bases` | Search across all KBs |
| `mcp__code-forge__list_knowledge_bases` | List all KBs |
| `mcp__code-forge__list_documents` | List documents in KB |
| `mcp__code-forge__get_kb_stats` | KB statistics |
| `mcp__code-forge__upload_document` | Save a document/memory |
| `mcp__code-forge__kb_lifecycle_health` | KB health report |
| `mcp__code-forge__kb_lifecycle_dedup` | Scan/merge duplicates |
| `mcp__code-forge__kb_lifecycle_consolidate` | LLM-powered merging |
| `mcp__code-forge__kb_lifecycle_archive` | Archive/restore documents |
---
## Guidelines
- Search memories before making architectural decisions
- Don't skip tests - Don't skip tests
- Don't create features without searching memories for existing patterns
- Don't end a session without saving key learnings - Don't end a session without saving key learnings
- Don't bypass established patterns without discussing first
## IMPORTANT: Project Context ## IMPORTANT: Project Context
@ -345,6 +124,5 @@ This file (CLAUDE.md) is automatically loaded at the start of every Claude Code
- Current architecture decisions - Current architecture decisions
- Team conventions - Team conventions
- Common gotchas - Common gotchas
- Frequently referenced information
**Update this file as the project evolves!** **Update this file as the project evolves!**

View file

@ -545,3 +545,149 @@ class TestSQLiteManagerSingleton:
manager = get_sqlite_manager() manager = get_sqlite_manager()
assert manager is not None assert manager is not None
assert hasattr(manager, 'db_path') assert hasattr(manager, 'db_path')
@pytest.mark.unit
class TestQueryDocumentsMultiKB:
"""Test cross-KB search functionality."""
def _add_docs(self, db, kb_name, docs):
"""Helper to add documents with embeddings to a KB."""
documents = [d["text"] for d in docs]
embeddings = [d["embedding"] for d in docs]
metadatas = [d.get("metadata", {}) for d in docs]
ids = [d["id"] for d in docs]
db.add_documents(kb_name=kb_name, documents=documents,
embeddings=embeddings, metadatas=metadatas, ids=ids)
def test_multi_kb_basic(self, clean_db):
"""Test searching across two KBs returns merged results."""
clean_db.create_collection("kb_a", KBType.GENERIC)
clean_db.create_collection("kb_b", KBType.GENERIC)
np.random.seed(10)
base = np.random.randn(768).astype(np.float32)
base = base / np.linalg.norm(base)
# KB_A: one doc very similar to query
perturbed_a = base + np.random.randn(768).astype(np.float32) * 0.01
perturbed_a = perturbed_a / np.linalg.norm(perturbed_a)
self._add_docs(clean_db, "kb_a", [
{"id": "a1", "text": "Document from KB A", "embedding": perturbed_a.tolist(),
"metadata": {"filename": "a1.md"}}
])
# KB_B: one doc less similar
perturbed_b = base + np.random.randn(768).astype(np.float32) * 0.05
perturbed_b = perturbed_b / np.linalg.norm(perturbed_b)
self._add_docs(clean_db, "kb_b", [
{"id": "b1", "text": "Document from KB B", "embedding": perturbed_b.tolist(),
"metadata": {"filename": "b1.md"}}
])
result = clean_db.query_documents_multi_kb(
kb_names=["kb_a", "kb_b"],
query_embedding=base.tolist(),
n_results=10
)
assert len(result["ids"]) == 2
assert len(result["documents"]) == 2
assert len(result["scores"]) == 2
# First result should have higher score
assert result["scores"][0] >= result["scores"][1]
# Each result should have _source_kb
kbs_found = {m["_source_kb"] for m in result["metadatas"]}
assert "kb_a" in kbs_found
assert "kb_b" in kbs_found
def test_multi_kb_dedup(self, clean_db):
"""Test that duplicate content across KBs is deduplicated."""
clean_db.create_collection("kb_x", KBType.GENERIC)
clean_db.create_collection("kb_y", KBType.GENERIC)
np.random.seed(20)
emb = np.random.randn(768).astype(np.float32)
emb = emb / np.linalg.norm(emb)
same_text = "Exact same content in both KBs for dedup testing"
self._add_docs(clean_db, "kb_x", [
{"id": "x1", "text": same_text, "embedding": emb.tolist(), "metadata": {}}
])
self._add_docs(clean_db, "kb_y", [
{"id": "y1", "text": same_text, "embedding": emb.tolist(), "metadata": {}}
])
result = clean_db.query_documents_multi_kb(
kb_names=["kb_x", "kb_y"],
query_embedding=emb.tolist(),
n_results=10
)
# Should only get 1 result after dedup
assert len(result["ids"]) == 1
def test_multi_kb_empty(self, clean_db):
"""Test searching with no matching KBs returns empty."""
result = clean_db.query_documents_multi_kb(
kb_names=["nonexistent_kb"],
query_embedding=[0.1] * 768,
n_results=5
)
assert result["ids"] == []
assert result["documents"] == []
assert result["scores"] == []
def test_multi_kb_respects_n_results(self, clean_db):
"""Test that n_results limit is respected."""
clean_db.create_collection("kb_limit", KBType.GENERIC)
np.random.seed(30)
base = np.random.randn(768).astype(np.float32)
base = base / np.linalg.norm(base)
docs = []
for i in range(5):
perturbed = base + np.random.randn(768).astype(np.float32) * 0.01
perturbed = perturbed / np.linalg.norm(perturbed)
docs.append({
"id": f"lim{i}", "text": f"Document {i} for limit test",
"embedding": perturbed.tolist(), "metadata": {}
})
self._add_docs(clean_db, "kb_limit", docs)
result = clean_db.query_documents_multi_kb(
kb_names=["kb_limit"],
query_embedding=base.tolist(),
n_results=2
)
assert len(result["ids"]) == 2
def test_multi_kb_score_ordering(self, clean_db):
"""Test that results are sorted by descending similarity score."""
clean_db.create_collection("kb_order", KBType.GENERIC)
np.random.seed(40)
base = np.random.randn(768).astype(np.float32)
base = base / np.linalg.norm(base)
# Add docs with varying similarity
docs = []
for i, noise in enumerate([0.01, 0.1, 0.5]):
perturbed = base + np.random.randn(768).astype(np.float32) * noise
perturbed = perturbed / np.linalg.norm(perturbed)
docs.append({
"id": f"ord{i}", "text": f"Document {i} noise={noise}",
"embedding": perturbed.tolist(), "metadata": {}
})
self._add_docs(clean_db, "kb_order", docs)
result = clean_db.query_documents_multi_kb(
kb_names=["kb_order"],
query_embedding=base.tolist(),
n_results=10
)
scores = result["scores"]
for i in range(len(scores) - 1):
assert scores[i] >= scores[i + 1], "Scores should be in descending order"