""" Query the knowledge base using index-guided retrieval (no RAG). The LLM reads the index, picks relevant articles, and synthesizes an answer. No vector database, no embeddings, no chunking - just structured markdown and an index the LLM can reason over. Usage: uv run python query.py "How should I handle auth redirects?" uv run python query.py "What patterns do I use for API design?" --file-back """ from __future__ import annotations import argparse import asyncio from pathlib import Path from config import KNOWLEDGE_DIR, QA_DIR, now_iso from utils import load_state, read_all_wiki_content, save_state ROOT_DIR = Path(__file__).resolve().parent.parent async def run_query(question: str, file_back: bool = False) -> str: """Query the knowledge base and optionally file the answer back.""" from claude_agent_sdk import ( AssistantMessage, ClaudeAgentOptions, ResultMessage, TextBlock, query, ) wiki_content = read_all_wiki_content() tools = ["Read", "Glob", "Grep"] if file_back: tools.extend(["Write", "Edit"]) file_back_instructions = "" if file_back: timestamp = now_iso() file_back_instructions = f""" ## File Back Instructions After answering, do the following: 1. Create a Q&A article at {QA_DIR}/ with the filename being a slugified version of the question (e.g., knowledge/qa/how-to-handle-auth-redirects.md) 2. Use the Q&A article format from the schema (frontmatter with title, question, consulted articles, filed date) 3. Update {KNOWLEDGE_DIR / 'index.md'} with a new row for this Q&A article 4. Append to {KNOWLEDGE_DIR / 'log.md'}: ## [{timestamp}] query (filed) | question summary - Question: {question} - Consulted: [[list of articles read]] - Filed to: [[qa/article-name]] """ prompt = f"""You are a knowledge base query engine. Answer the user's question by consulting the knowledge base below. ## How to Answer 1. Read the INDEX section first - it lists every article with a one-line summary 2. Identify 3-10 articles that are relevant to the question 3. Read those articles carefully (they're included below) 4. Synthesize a clear, thorough answer 5. Cite your sources using [[wikilinks]] (e.g., [[concepts/supabase-auth]]) 6. If the knowledge base doesn't contain relevant information, say so honestly ## Knowledge Base {wiki_content} ## Question {question} {file_back_instructions}""" answer = "" cost = 0.0 try: async for message in query( prompt=prompt, options=ClaudeAgentOptions( cwd=str(ROOT_DIR), system_prompt={"type": "preset", "preset": "claude_code"}, allowed_tools=tools, permission_mode="acceptEdits", max_turns=15, ), ): if isinstance(message, AssistantMessage): for block in message.content: if isinstance(block, TextBlock): answer += block.text elif isinstance(message, ResultMessage): cost = message.total_cost_usd or 0.0 except Exception as e: answer = f"Error querying knowledge base: {e}" # Update state state = load_state() state["query_count"] = state.get("query_count", 0) + 1 state["total_cost"] = state.get("total_cost", 0.0) + cost save_state(state) return answer def main(): parser = argparse.ArgumentParser(description="Query the personal knowledge base") parser.add_argument("question", help="The question to ask") parser.add_argument( "--file-back", action="store_true", help="File the answer back into the knowledge base as a Q&A article", ) args = parser.parse_args() print(f"Question: {args.question}") print(f"File back: {'yes' if args.file_back else 'no'}") print("-" * 60) answer = asyncio.run(run_query(args.question, file_back=args.file_back)) print(answer) if args.file_back: print("\n" + "-" * 60) qa_count = len(list(QA_DIR.glob("*.md"))) if QA_DIR.exists() else 0 print(f"Answer filed to knowledge/qa/ ({qa_count} Q&A articles total)") if __name__ == "__main__": main()