Skip to content

Skill-Seekers evaluation — multi-source ingest infrastructure vs KH platform fit

Skill-Seekers evaluation — multi-source ingest infrastructure vs KH platform fit

Section titled “Skill-Seekers evaluation — multi-source ingest infrastructure vs KH platform fit”

Date: 2026-05-08 Branch: content-items-investigation Author: Claude Code session (grounded review of upstream development branch + KH ingest+chunk infrastructure) Subject: yusufkaraaslan/Skill_Seekers development branch (v3.5.0+, ~13.4k stars, MIT, Python 3.10+) — “Convert documentation websites, GitHub repositories, and PDFs into Claude AI skills with automatic conflict detection” Status: Evaluation only — no production integration changes proposed without explicit decision. Per parent-session feedback: bias toward re-use of battle-tested infrastructure; “what should we be doing” not “what’s lowest disruption”. Repository default branch: development (NOT main). Predecessors: Phase 0.7 synthesis (canonical pipeline + revised re-ingest readiness gate) + parent feedback in 07-synthesis-feedback.md (storage may not be required; client wants better RAG retrieval; biggest UX unlock = re-upload UPDATEs existing content_items).


1. What skill-seekers is (in KH-relevant terms)

Section titled “1. What skill-seekers is (in KH-relevant terms)”

Skill-Seekers is, structurally, a 17-source ingest+structure+export pipeline for Claude Skills, written in Python, with a generic merge layer (“Unified Scraping”), a shipped MCP server (40 tools across 7 categories), and bolt-on confidence/quality/conflict-detection capabilities. The “convert to skill” is the terminal artefact (a SKILL.md + references/*.md directory + manifest); upstream of that, the entire pipeline mirrors the kind of infrastructure KH currently spreads across lib/ai/extract-content.ts, lib/extraction/*, lib/bid-library-ingest/*, lib/content/chunking.ts, lib/content/chunk-store.ts, and scripts/kb_pipeline/extract.py.

The architectural core (per src/skill_seekers/cli/skill_converter.py):

SkillConverter (base class)
├─ extract() ← per-source-type adapter
└─ build_skill() ← canonical post-processing
CONVERTER_REGISTRY: {
"web": DocToSkillConverter,
"github": GitHubScraper,
"pdf": PDFToSkillConverter,
"word": WordToSkillConverter, # mammoth + python-docx
"epub": EpubToSkillConverter,
"video": VideoToSkillConverter, # YouTube/Vimeo/local + transcript
"local": CodebaseAnalyzer, # 9 languages, AST/regex
"jupyter": JupyterToSkillConverter,
"html": HtmlToSkillConverter,
"openapi": OpenAPIToSkillConverter, # 2.0 / 3.0 / 3.1
"asciidoc": AsciiDocToSkillConverter,
"pptx": PptxToSkillConverter,
"rss": RssToSkillConverter,
"manpage": ManPageToSkillConverter,
"confluence": ConfluenceToSkillConverter,
"notion": NotionToSkillConverter,
"chat": ChatToSkillConverter,
"config": UnifiedScraper # multi-source merge
}

This is exactly the canonical-pipeline shape the 0.7 synthesis recommends KH adopt: one extract adapter per input shape, one shared canonical core for everything downstream. Skill-Seekers ships that shape today, battle-tested at 13.4k-star scale, with 17 adapter implementations already written.

Surface-area scale (informative, not prescriptive):

Sub-systemFilesPurpose
cli/ (94 modules)scrapers + analyzers + utilities + storage adaptorsPer-source extractors, code analysis (9 languages), conflict detection, quality metrics, RAG chunker, embedding pipeline
cli/parsers/ (27 modules)argparse parsers for each skill-seekers <subcommand>CLI surface for ~30 subcommands
cli/storage/ (4 modules)s3, azure_storage, gcs_storage, base_storageCloud storage adaptors (S3, Azure, GCP)
embedding/ (4 modules)cache.py, generator.py, models.py, server.pyEmbedding generation with cache + cost tracking
mcp/server.py, server_fastmcp, server_legacy, source_manager, marketplace_manager, marketplace_publisher, agent_detector, config_publisher, git_repo, tools/40-tool MCP surface
sync/detector.py, monitor.py, notifier.pySource sync (poll for upstream doc changes)
workflows/ (50+ YAML presets)accessibility-a11y.yaml, architecture-comprehensive.yaml, …Per-domain enhancement workflows

Wall-clock comparison: KH’s TS+Python ingest infrastructure (lib/extraction/, lib/ai/, lib/bid-library-ingest/, scripts/kb_pipeline/, lib/content/) totals roughly 30-40 files of focused extract/chunk code. Skill-Seekers ships ~94 CLI modules, but the load-bearing pipeline-relevant subset (RAGChunker, MarkdownCleaner, conflict_detector, embedding_pipeline, doc_scraper, codebase_scraper, pdf_scraper, github_fetcher, openapi_scraper, word_scraper, code_analyzer, dependency_analyzer, quality_metrics) is ~15-20 modules. Comparable scale to KH’s current ingest stack — but with adapters KH does not have (epub, jupyter, html, asciidoc, pptx, manpage, confluence, notion, chat, openapi, rss).


2. Tool-specific lens — direct evaluation against the 9 questions in the brief

Section titled “2. Tool-specific lens — direct evaluation against the 9 questions in the brief”

2.1 Q1 — Direct P4/P7/P9 replacement candidate?

Section titled “2.1 Q1 — Direct P4/P7/P9 replacement candidate?”

KH paths in scope:

  • P4 (/api/ingest/url) — TS URL extractor: extractFromUrl() in lib/extraction/url.ts → Readability+jsdom (HTML) or unpdf (PDF) → Turndown markdown.
  • P7 (/api/upload) — TS multipart binary: unpdf (PDF) / mammoth+turndown (DOCX) / passthrough (MD/TXT). Sole writer of source_documents. Silent-fail at L408-447.
  • P9 (lib/intelligence/pipeline.ts) — RSS 4-tier extractor: rss_contentfetch+turndownjina_readerfirecrawl.

Skill-Seekers equivalents:

KH PathCurrent implementationSkill-Seekers equivalentVerdict
P4 URLextractFromUrl() (32 LOC) → extractFromHtml() (Readability+turndown) / extractPdfText() (unpdf)doc_scraper.py (DocToSkillConverter) — BeautifulSoup + httpx + custom selectors with 23 listed FALLBACK_MAIN_SELECTORS, llms.txt detection (LlmsTxtDetector/LlmsTxtParser), LanguageDetector, per-domain rate limiting, resume/checkpoint, async crawl mode. Plus pdf_scraper.py with chapter detection + page chunking + table extraction (B1.3).PARTIAL replacement candidate. Skill-Seekers’s doc_scraper.py is more sophisticated than KH’s extractFromHtml() — it handles llms.txt, custom selectors per docs site, sitemap discovery, rate-limit-aware scraping. But it is HTML-tree-walking, not Readability-based; for single-URL Readability extraction (the typical KH user case: “I read this article, save it”), KH’s Readability path is simpler and arguably better for general-web-page → article-text extraction. Hybrid recommended: keep Readability for single-URL save, add Skill-Seekers’s pattern for bulk-docs-site ingestion (a use case KH doesn’t currently serve — “ingest all of vendor’s API docs at once”).
P7 Binaryunpdf + mammoth+turndown two-step (per CLAUDE.md gotcha)pdf_scraper.py + pdf_extractor_poc.py — uses pdfplumber (not unpdf); supports OCR for scanned PDFs (enable_ocr), encrypted PDFs (password), image extraction with min_image_size, chapter detection + page chunking + code-block-merging across pages. word_scraper.py uses mammoth + python-docx (same toolchain as KH).STRONG replacement candidate for PDF. Skill-Seekers’s PDF pipeline handles features KH’s unpdf does not: chapters, OCR, password-protected PDFs, images. KH’s unpdf is fast but minimal — text-only, no structure preservation. Re: DOCX, same toolchain (mammoth), so substituting Skill-Seekers’s word_scraper.py for KH’s two-step gets you the same output but with built-in metadata extraction (subject, title, keywords). KH’s DOCX → Q&A-table parser (extractQaPairs(), 498 LOC) is more domain-specific than anything Skill-Seekers offers and would NOT be replaced.
P9 RSS4-tier cascade: rss_contentfetch+turndownjina_readerfirecrawlrss_scraper.py (RssToSkillConverter) — RSS/Atom feed extraction. Not a 4-tier cascade. Single-source, batch-style.NOT a replacement. P9’s pre-content discovery + relevance gating + 4-tier extraction is KH-specific intelligence-pipeline architecture (per 0.1 P9 audit). Skill-Seekers’s rss adapter is a flat “fetch the feed, extract entries” — useful for batch ingestion of an RSS archive, not for live polling + relevance scoring. No collapse here.

Headline verdict for Q1: HYBRID adoption is the right answer, not full replacement.

  • Adopt Skill-Seekers doc_scraper.py patterns for bulk-documentation-site ingestion (a new use case KH doesn’t have yet — “ingest the vendor’s whole docs site at once”). This unlocks the “bulk knowledge import” workflow the client will eventually want.
  • Adopt Skill-Seekers pdf_scraper.py as a P7 upgrade — gain OCR, chapter detection, image extraction. Risk: pdfplumber vs unpdf is a different dependency footprint.
  • Adopt Skill-Seekers word_scraper.py metadata-extraction patterns — gain document-properties (subject, title, keywords) extraction that KH currently ignores.
  • Keep Readability for single-URL article extraction — Skill-Seekers’s tree-walking is overkill here.
  • Keep KH’s Q&A docx parser — domain-specific, irreplaceable.
  • Keep KH’s P9 RSS pipeline — not a Skill-Seekers competency.

2.2 Q2 — MarkdownCleaner replaces mammoth → turndown two-step?

Section titled “2.2 Q2 — MarkdownCleaner replaces mammoth → turndown two-step?”

KH today (per CLAUDE.md gotcha):

“mammoth convertToMarkdown() drops tables: Use two-step mammoth.convertToHtml() → Turndown (with turndown-plugin-gfm).”

docxBufferToMarkdown() in lib/bid-library-ingest/docx-to-markdown.ts (45 LOC):

const { value: html } = await mammoth.convertToHtml(input);
return sharedTurndown.turndown(html).trim();

Turndown is configured with: headingStyle: 'atx', bulletListMarker: '-', codeBlockStyle: 'fenced', gfm plugin. KH also has rules to drop empty links, scripts, styles (lib/extraction/turndown.ts).

Skill-Seekers’s MarkdownCleaner (per src/skill_seekers/cli/markdown_cleaner.py):

class MarkdownCleaner:
@staticmethod
def remove_html_tags(text: str) -> str:
# Remove HTML comments, then HTML tags but keep content
text = re.sub(r"<!--.*?-->", "", text, flags=re.DOTALL)
text = re.sub(r"<[^>]+>", "", text)
text = re.sub(r"\n\s*\n\s*\n+", "\n\n", text)
return text.strip()
@staticmethod
def extract_first_section(text: str, max_chars: int = 500) -> str:
# Smart: respects code-fence state, captures first 4 sections, truncates at sentence
...

Verdict: MarkdownCleaner does NOT replace the mammoth → Turndown flow. They solve different problems:

  • mammoth → Turndown = “convert binary DOCX bytes to GFM markdown including table preservation”. This is bytes-in, markdown-out. It is the extraction step.
  • MarkdownCleaner = “given markdown that already has HTML residue (e.g., from mixed-source extraction), strip the HTML tags while preserving structure. Also extract the first-section preview.” This is markdown-in, cleaner-markdown-out. It is a post-processing step.

The two would compose in series, not substitute:

DOCX bytes → mammoth.convertToHtml → Turndown.turndown → MARKDOWN (with HTML residue if mammoth left any)
MarkdownCleaner.remove_html_tags → CLEAN MARKDOWN

Therefore: do NOT replace KH’s two-step DOCX flow. Optionally add MarkdownCleaner-style post-cleanup to lib/extraction/clean-mdx-tags.ts (which already exists for MDX-tag stripping but doesn’t aggressively remove generic HTML residue). MarkdownCleaner’s extract_first_section() is also useful for the summary preview / first-paragraph extraction that KH currently does inside the AI summarise call — it could be a deterministic free-text fallback for items where AI summary fails.

Net Q2 verdict: NO direct replacement; SMALL adoption opportunity for cleanup helpers (MarkdownCleaner.remove_html_tags + extract_first_section). ~1-2h port to TS if desired. Low priority.

2.3 Q3 — RAGChunker replaces regenerateChunks()?

Section titled “2.3 Q3 — RAGChunker replaces regenerateChunks()?”

This is the most operationally important question in the brief. The 0.7 synthesis surfaced two WILL-FIX-now items (RSS chunks regen + batch chunks regen) where chunks weren’t generated for 28 prod rows because of a wiring gap (“the most operationally useful failure mode KH has surfaced this phase” per 0.7 synthesis §6.1). Could a battle-tested RAGChunker eliminate this class of bug?

KH today:

  • chunkByHeadings() in lib/content/chunking.ts (220 LOC) — heading-boundary chunking; H2 default, H1 fallback, single-chunk when <500 chars or no splittable headings; min-chunk-merge 100 chars; word/char counts.
  • regenerateChunks() in lib/content/chunk-store.ts (203 LOC) — DELETE existing + chunk + embed (parallel) + INSERT + parent-FK update pass. 5 callers (markdown-orchestrator.ts, mcp/tools/content.ts, mcp/tools/governance.ts, app/api/ingest/url/route.ts, app/api/items/route.ts).
  • Python mirror: chunk_by_headings() + store_chunks() in scripts/kb_pipeline/chunk.py (286 LOC, regex-based heading detection).
  • Embedding via text-embedding-3-large @ 1024 dims (Matryoshka); 24,000-char input cap.

Skill-Seekers’s RAGChunker (per src/skill_seekers/cli/rag_chunker.py):

class RAGChunker:
"""Semantic chunker for RAG pipelines.
Features:
- Preserves code blocks (don't split mid-code) ← uses placeholder swap
- Preserves paragraphs (semantic boundaries via \n\n+ regex)
- Adds metadata (source, category, chunk_id)
- Configurable chunk size (DEFAULT_CHUNK_TOKENS) and overlap (DEFAULT_CHUNK_OVERLAP_TOKENS)
"""
def __init__(self, chunk_size, chunk_overlap, preserve_code_blocks=True,
preserve_paragraphs=True, min_chunk_size=100): ...
def chunk_document(text, metadata, source_file): ...
def chunk_skill(skill_dir): ...
def estimate_tokens(text): return len(text) // 4 # 4-chars-per-token heuristic

Side-by-side comparison:

AspectKH chunkByHeadingsSkill-Seekers RAGChunker
Chunking strategyHeading-boundary (H2 default, H1 fallback) — semantic split-pointsParagraph-and-section-boundary (\n\n+, then \n#{1,6}, then \n) with chunk-size budget enforcement — character-budget split
Code block safetyYes — uses marked lexer to tokenise; code blocks detected as {type: 'code'}Yes — uses placeholder-swap (<<CODE_BLOCK_n>>) to extract before split, reinsert after
OverlapNone — each chunk is exclusiveConfigurable (chunk_overlap tokens) — overlap at boundaries to preserve context across chunks
Min-chunk mergeYesMIN_CHUNK_CHARS=100 merges with next siblingYesmin_chunk_size=100 skips chunks below threshold
Max-chunk sizeNone (relies on heading granularity)Yeschunk_size token budget enforced; artificial boundaries inserted if natural boundaries are sparse
Metadata modelheading_text, heading_level, heading_path[], position, parent_position, char_count, word_countchunk_id, chunk_index, total_chunks, estimated_tokens, has_code_block, source, category, file_type, source_file, plus user-supplied metadata dict
HierarchyYesparent_chunk_id FK chain via findParentPosition()No — flat chunk_index order
EmbeddingSeparate (generateEmbedding per chunk in chunk-store.ts)Separate (embedding_pipeline.py — multi-provider + cache)
Storagecontent_chunks Postgres table with FK to content_itemsJSON file (rag_chunks.json) for downstream loading by vector DB
Wiring (KH)5 caller sites; 2 known wiring gaps (P6 batch + P9 RSS) producing 28 chunkless rowsn/a (Skill-Seekers always called by unified_skill_builder.py after extract)

Critical architectural difference: KH uses heading-boundary chunking; RAGChunker uses paragraph-and-section-boundary chunking with token-budget enforcement.

This is not just an implementation difference — it’s a different retrieval philosophy.

  • KH heading-based: “the most natural retrieval unit is a section under a H2 heading, regardless of length”. Optimised for documents with strong heading hierarchy (Q&A pairs, structured policies, technical reference docs). Yields varying-size chunks (some 200 chars, some 8000 chars).
  • RAGChunker token-budget: “every chunk should be similar size for embedding-quality consistency, with overlap to preserve context across boundaries”. Optimised for narrative documents (PDF books, blog posts, LLM training data). Yields uniform-size chunks (~512-2000 tokens each).

Which is right for KH? This depends on the corpus:

  • Q&A pairs (71% of prod content per 0.7 synthesis) → KH’s heading-based is correct. Each Q&A is naturally heading-bounded; uniform-size chunks would split a Q across two chunks, destroying retrieval coherence. Client feedback Item 2 already says retrieval is missing answers; uniform chunking would make this worse, not better.
  • Long-form policies / technical reference / bid documentseither works, but heading-based preserves document structure that’s user-meaningful.
  • PDFs with weak heading structure / scanned docs / chat logsRAGChunker’s token-budget is correct. KH’s heading-based falls back to “whole document = one chunk” for headingless docs; for a 50-page PDF that’s catastrophic for retrieval.

Verdict on Q3:

Do NOT replace KH’s heading-based chunking. It is better than RAGChunker’s paragraph-budget for KH’s dominant content shape (Q&A pairs).

DO consider adopting RAGChunker’s token-budget overlap pattern as a SECOND chunking mode, used only when:

  1. Heading detection finds no headings at all (today: degenerates to single-chunk-per-document — bad for retrieval), or
  2. Document length exceeds N words AND average heading-density is low (< 1 heading per 2000 words).

This would be a ~150-LOC addition to lib/content/chunking.ts — gated by a chunkingMode: 'heading' | 'token-budget' parameter on regenerateChunks(). KH would default to 'heading' for Q&A and most uploads; switch to 'token-budget' for very-long-form binary uploads where heading structure is absent.

Will RAGChunker eliminate the wiring-gap bug class? No — that’s not a chunking-algorithm problem; it’s a missing-call-site problem. P6 batch and P9 RSS don’t call regenerateChunks() at all. Whether the chunker is heading-based or token-budget makes zero difference to a missing call site. The fix per 0.7 synthesis §5.1 is to wire the call — total effort ~30min per path. Adopting RAGChunker would NOT prevent this class of bug; only the canonical-pipeline collapse (where chunking happens once in Layer 4 of 0.7-synthesis.md §2) prevents it.

Net Q3 verdict: NO direct replacement; SMALL adoption opportunity for token-budget chunking as a fallback mode for headingless corpora. ~150 LOC. Medium priority once canonical-pipeline lands. Adopting it does NOT eliminate the wiring-gap bug class — that’s solved structurally by canonical-pipeline collapse, not by chunker choice.

2.4 Q4 — Smart metadata + automatic conflict detection — solves client feedback Item 3?

Section titled “2.4 Q4 — Smart metadata + automatic conflict detection — solves client feedback Item 3?”

Client feedback Item 3 (verbatim, from kh-client-feedback.md):

“Hub needs hard scope tags on every content item. The most damaging mistakes I’ve had to catch today weren’t search misses — they were the AI confidently pulling correct content from the wrong domain. Two examples. The KB has an entry on Bitdefender EDR which is correctly tagged in the source library as Internal IT — Endpoint Security (i.e. staff laptops). When the AI was answering NCSC Principle 2.3 (data at rest) and Principle 5.3 (protective monitoring) for our production infrastructure, it pulled the Bitdefender content into both because it sat under “malware protection” with no scope flag.”

“Suggested taxonomy: internal-it (staff/office systems), production-infrastructure (client-facing servers and hosting), application-layer (LMS/AA/Websites code), office-physical (Phew premises), data-centre-physical (Telehouse, Nimbus). Anti-tags on commonly conflated items would help too — e.g. the Bitdefender entry should carry an explicit ‘does not apply to: production infrastructure’ flag that an AI or person can see at a glance.”

Skill-Seekers’s metadata + conflict-detection model:

ConflictDetector (per src/skill_seekers/cli/conflict_detector.py):

@dataclass
class Conflict:
type: str # 'missing_in_docs' | 'missing_in_code' | 'signature_mismatch' | 'description_mismatch'
severity: str # 'low' | 'medium' | 'high'
api_name: str
docs_info: dict | None
code_info: dict | None
difference: str | None
suggestion: str | None

The use case Skill-Seekers solves: “the docs and the code disagree about a function’s signature; surface the disagreement so users know which to trust”. It’s a docs-vs-code drift detector for software libraries — designed for “is the React docs lying about useState’s parameters?”, not “is this content scoped to internal-IT or production?”.

Verdict: Skill-Seekers’s conflict-detection does NOT solve the LBBD-CSP scope-tag problem. They are different problems:

  • Skill-Seekers’s problem: two SOURCES of truth disagree about the SAME entity (docs say useState(initial), code says useState(initial, options?)).
  • KH/client problem: ONE source of truth has insufficient scoping — the Bitdefender EDR entry has no annotation that it applies to staff laptops not production servers. There is no “second source” to compare against.

However — Skill-Seekers’s per-config categories field is genuinely interesting for the scope-tag problem. From docs/reference/CONFIG_FORMAT.md:

{
"categories": {
"getting_started": ["learn", "tutorial", "intro"],
"api": ["reference", "api", "hooks"]
}
}

This is a keyword-driven categorisation rule applied at scrape-time. Each scraped page is bucketed into getting_started if its title/URL contains “learn”/“tutorial”/“intro”, api if it contains “reference”/“api”/“hooks”, etc. Output: each chunk in references/{category}.md is implicitly scope-tagged.

Does this map to the client’s scope taxonomy? Partially:

  • Multi-keyword rule could express internal-it: ["staff", "laptop", "office network", "endpoint"], production-infrastructure: ["server", "hosting", "AWS", "production"], etc.
  • Anti-tags are NOT supported in Skill-Seekers’s model — there’s no “this content does NOT apply to X” flag.
  • Rule conflicts (a chunk matches both internal-it and production-infrastructure keywords) are resolved by first-match-wins, not reported. The client wants conflicts SURFACED, not silently resolved.

The client’s actual ask, mapped to KH primitives:

Client requirementKH primitive that should solve itWhat’s needed
Mandatory scope tag on every content itemcontent_items typed column or entity_relationships rowNew typed enum column (scope_tag with CHECK constraint) OR scope-typed entity in entity_mentions (e.g. entity_type=scope, name=internal-it). Per 0.7 entity classification reframe.
Anti-tags (“does not apply to: X”)Same column/relationship pattern, negative-polarity flagLikely a separate anti_scope_tags text[] column or entity_relationships rows with relation_type=does_not_apply_to
Surface in every search resultMCP search response shape + UI metadata sidebarField added to search_knowledge_base MCP response; metadata-sidebar.tsx shows scope chip
AI must respect scope when retrievingChunk metadata + retrieval filterscope_tag on each chunk; MCP search accepts scope_filter param; high-confidence-wrong-scope answers blocked at retrieval, not generation

This is a KH/canonical-pipeline architectural question, not a third-party-tool integration. Skill-Seekers’s categories keyword-rule pattern is a useful inspiration (deterministic post-classify scope inference), but KH should implement it as part of its own classification pipeline because:

  1. It needs typed-column enforcement (CHECK constraint) for safety.
  2. It needs anti-tags, which Skill-Seekers doesn’t model.
  3. It needs conflict surfacing (a chunk matches multiple scopes → flag for review), which Skill-Seekers doesn’t do.
  4. It needs per-tenant taxonomy (Phew uses internal-it / production-infrastructure / ...; another client may have different scopes), and Skill-Seekers’s categories is per-config (per-skill), not a centralised taxonomy.

Net Q4 verdict: Skill-Seekers’s conflict-detection does NOT directly solve the scope-tag problem. Skill-Seekers’s categories keyword-rule pattern is useful inspiration. The right home for the client’s scope-tag taxonomy is KH’s classification pipeline + entity_relationships + a new scope_tag typed column on content_items (or a dedicated content_item_scope_tags table for many-to-many + anti-tags).

Recommended action: add a new work-package “OPS-X-SCOPE-TAGS” addressing client feedback Item 3, sized ~1-2 weeks (DB column + classification rule + MCP response shape + UI surface). Proceed independently of Skill-Seekers integration.

2.5 Q5 — Documentation Gap Analysis + GH Triple-Stream + Codebase Analysis (C3.x) — supplements Phase 0.2.5?

Section titled “2.5 Q5 — Documentation Gap Analysis + GH Triple-Stream + Codebase Analysis (C3.x) — supplements Phase 0.2.5?”

Phase 0.2.5 (build-not-wired audit) catalogued ~17 build-not-wired patterns — places where code is written but never invoked from production. Examples: detectQAPairs() (zero callers), auto_supersede flag (parsed but unused), Re-classify after save toggle (declared but never wired), missing regenerateChunks calls in P6/P9.

Skill-Seekers C3.x (per docs/reference/C3_x_Router_Architecture.md):

“Three-Stream Source Integration: GitHub as multi-source provider — Code → C3.x, Docs → Markdown, Issues → Insights. C3.x as depth mode (basic/deep), not separate tool.”

C3.x is Skill-Seekers’s codebase analysis at three depths (surface, standard/deep, comprehensive/full):

  • Surface: file tree only.
  • Deep (default): structural analysis — methods, parameters, relationships. ~10ms/class.
  • Full: behavioural analysis — code patterns, instance caching, thread safety detection. ~20ms/class.

Plus 9 supporting analysers in cli/:

  • code_analyzer.py — extract function/class signatures via AST (Python) or regex (8 other languages).
  • dependency_analyzer.py — import-graph extraction + circular-dependency detection via NetworkX.
  • pattern_recognizer.py — Singleton, Factory, Builder, Observer, Strategy, Decorator, etc. detection.
  • architectural_pattern_detector.py — higher-level architectural patterns.
  • signal_flow_analyzer.py — Godot-specific (signals/slots).
  • api_reference_builder.py — generates markdown API docs from analysed signatures.
  • test_example_extractor.py — extracts usage examples from tests.

Documentation Gap Analysis (per docs/features/UNIFIED_SCRAPING.md):

“Detects conflicts between documentation and actual code implementation. Highlights discrepancies with inline warnings.”

This runs the ConflictDetector post-extraction on a unified config (docs+code). Output: list of Conflict instances surfacing missing/mismatch discrepancies.

How this maps to Phase 0.2.5:

Phase 0.2.5 findingCould Skill-Seekers detect this?Verdict
detectQAPairs() exported but zero callersYes (partially)dependency_analyzer.py builds the import graph; isolated nodes (zero imports) surface as a separate dataset. Not directly framed as “build-not-wired” but the data is there.Useful supplement. Cheaper than the manual 0.2.5 pass once running.
auto_supersede flag declared but never readNo — that requires data-flow analysis (track field reads, not just imports). Skill-Seekers doesn’t do data-flow.Not detectable.
Re-classify after save toggle declared but never wiredNo — same data-flow gap.Not detectable.
Missing regenerateChunks call in P6/P9Possibly — if P6’s route.ts doesn’t import/call regenerateChunks, the dependency graph would NOT show that edge. But the expected edge isn’t documented anywhere, so Skill-Seekers can’t say “expected but missing”; it can only say “this function is not called from this file”.Weakly detectable — only by hand-comparing call graphs, not auto-flagging.
Type-coverage drift (P6 has quality_score=0 writes when classifyContent returns valid scores)No — that requires runtime behaviour check, not static analysis.Not detectable.
Schema-vs-code drift (e.g. column exists in DB but no TS code reads or writes it)No — Skill-Seekers’s conflict detection is docs-vs-code, not schema-vs-code. KH would need a dedicated tool (Supabase MCP list_tables cross-referenced against grep of supabase.from('content_items')).Not detectable.

Triple-Stream Analysis (Code/Docs/Issues split for GitHub repos) is not relevant to KH because KH isn’t analysing public open-source GitHub repos for skill generation — it’s ingesting client documentation. The “issues” stream specifically captures GitHub bug reports, which is irrelevant.

Verdict on Q5: Skill-Seekers’s codebase analysis is a USEFUL SUPPLEMENT to Phase 0.2.5 manual audit, but NOT a replacement. Specifically:

  • dependency_analyzer.py could be a third tool alongside knip and graphify for detecting unused exports / isolated functions. Knip catches unused exports of typed TypeScript symbols; Graphify catches isolated nodes in the call graph; Skill-Seekers’s dependency_analyzer.py would catch cross-language call gaps (TS → Python) that neither Knip nor Graphify natively handles.
  • It does NOT replace data-flow audits. P0-1 silent-fail, swallow-catch patterns, schema-vs-code drift, build-not-wired-toggle-flags — these all need human or AST data-flow tracing. Skill-Seekers doesn’t do data-flow.
  • The Triple-Stream model is irrelevant to KH (we don’t ingest public GitHub repos).

Net Q5 verdict: SMALL adoption opportunity for dependency_analyzer.py as a third “build-not-wired-detector” alongside Knip + Graphify. ~1-2 days integration. Optional.

2.6 Q6 — API Extraction — relevant to “extract from API endpoint as a content type”?

Section titled “2.6 Q6 — API Extraction — relevant to “extract from API endpoint as a content type”?”

KH context: “extract from API endpoint as a content type” comes up periodically — e.g., “the client has a Swagger spec for their internal API; can we ingest it into the KB so AI can answer ‘how do I authenticate against the foo API?’ from the spec?”

Skill-Seekers’s API extraction:

OpenAPIToSkillConverter (per src/skill_seekers/cli/openapi_scraper.py) — handles OpenAPI 2.0 (Swagger), 3.0, 3.1 in YAML and JSON, from local files or remote URLs. Extracts:

  • API info (title, description, version, contact, license)
  • Servers / host / basePath
  • All paths with operations (GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS/TRACE)
  • Parameters (path, query, header, cookie, body)
  • Request bodies and response schemas
  • Component schemas / definitions with properties, types, enums
  • Security schemes (apiKey, http, oauth2, openIdConnect)
  • Tags for endpoint grouping

Output: per-endpoint markdown reference files in references/api/.

api_reference_builder.py does the same thing but for code-extracted APIs (from code_analyzer.py).

Verdict on Q6: STRONG ADOPTION CANDIDATE. This is a feature KH does not have today — the platform has zero OpenAPI/Swagger awareness — and it would extend KH’s content-type taxonomy in a useful direction:

content_type = 'api_specification'
+ source_documents row with mime_type='application/yaml' or 'application/json'
+ extracted markdown in content_items.content (per-endpoint sub-sections)
+ entity_mentions: each endpoint as entity_type='api_endpoint'
+ entity_relationships: endpoints linked to security schemes, parameters, schemas

Effort: porting openapi_scraper.py to TS or wrapping it as a Python adapter callable from canonical pipeline. Skill-Seekers’s implementation is ~600 LOC; a TS port using swagger-parser npm package would be ~200-300 LOC. Either way, ~1 week of work. Adds a new shape adapter to canonical pipeline (shape='api-spec').

Side benefit: OpenAPI extraction unlocks “auto-generate test queries against this API” workflows, which is interesting for the bid management product (e.g., “given the LBBD CSP questionnaire’s API endpoints, validate the answers automatically”).

Net Q6 verdict: STRONG ADOPTION. Add openapi shape adapter to canonical pipeline post-Phase A. ~1 week effort. New product capability.

2.7 Q7 — Vector DB export targets pgvector?

Section titled “2.7 Q7 — Vector DB export targets pgvector?”

KH today: content_chunks.embedding vector(1024) via Supabase pgvector 0.8.0. The single source of truth for retrieval embeddings.

Skill-Seekers’s vector DB exports (per docs/reference/MCP_REFERENCE.md §Vector Database Tools, 4 tools):

TargetMCP toolImplementation
Weaviateexport_to_weaviateexamples/weaviate-example/
ChromaDBexport_to_chromaexamples/chroma-example/
FAISSexport_to_faissexamples/faiss-example/
Qdrantexport_to_qdrantexamples/qdrant-example/

Confirmed via repository tree search (gh api repos/.../git/trees/development?recursive=1):

  • docs/integrations/CHROMA.md, FAISS.md, QDRANT.md, WEAVIATE.md — 4 integration guides.
  • .github/workflows/test-vector-dbs.yml, vector-db-export.yml — CI for these 4 targets.
  • Examples directories examples/{chroma,faiss,qdrant,weaviate}-example/ — quickstart code for each.

There is NO pgvector / Postgres / Supabase target in Skill-Seekers. The 4-target list is exhaustive.

Why this matters for KH:

KH cannot consume Skill-Seekers’s chunked-embeddings output via MCP export_to_* tools because the destination would be one of those 4 vector DBs, not pgvector. A pipeline like:

DOCX → Skill-Seekers extract → Skill-Seekers chunk → Skill-Seekers embed → export_to_chroma

ends with the chunks in ChromaDB, not in content_chunks Postgres. KH would need either (a) a new export_to_pgvector adapter contributed upstream to Skill-Seekers, or (b) a custom integration where KH pulls the JSON output (rag_chunks.json) from Skill-Seekers and writes its own pgvector rows.

Effort to add export_to_pgvector (option a): each existing exporter is ~150-300 LOC of straightforward “iterate chunks, INSERT rows” code (per the example 2_upload_to_chroma.py). Adding pgvector is one of:

  • Direct PG INSERT via psycopg2 (~200 LOC) — straightforward.
  • Supabase REST API via supabase-py (~150 LOC, simpler).
  • Upstream PR to Skill-Seekers to add this capability (community contribution; rejected risk if maintainers prioritise the 4 named targets only).

Effort for option b (KH consumes rag_chunks.json and writes pgvector itself): the JSON shape is documented in RAGChunker.save_chunks():

[{
"chunk_id": str,
"page_content": str, # markdown text
"metadata": {chunk_index, total_chunks, estimated_tokens, has_code_block, source, category, ...}
}, ...]

KH just needs a new endpoint or CLI taking this JSON, computing 1024-dim embeddings via OpenAI, and INSERTing to content_chunks. ~50-80 LOC of TS or Python. Trivial.

Verdict on Q7: Skill-Seekers does NOT export to pgvector. This is a real integration gap. The two viable paths are:

  1. Upstream contribution — add export_to_pgvector to Skill-Seekers via PR. Benefits the community; risk of being rejected or stalled in review. ~1-2 weeks elapsed time.
  2. KH-side consumer — KH ingests rag_chunks.json produced by Skill-Seekers, computes embeddings via OpenAI, INSERTs to content_chunks. ~50-80 LOC. Same week as wiring decision.

Net Q7 verdict: PARTIAL FIT. Skill-Seekers’s vector-DB-export competency is centred on Weaviate/Chroma/FAISS/Qdrant. KH on pgvector. Adopt the JSON-output handoff (option 2) if integrating; submit upstream PR if there’s strategic value (option 1).

2.8 Q8 — Re-use vs integrate vs reinvent vs hybrid — final verdict

Section titled “2.8 Q8 — Re-use vs integrate vs reinvent vs hybrid — final verdict”

Per parent-session feedback (07-synthesis-feedback.md):

“P4 TS URL ingest & P7 TS file upload — interested to understand how the following third-party tools may be beneficial here, keeping in mind the feedback I provided in the graphify evaluation feedback doc, around ‘re-use’ and ‘integration’ versus re-inventing the wheel — cocoindex, pullmd, and skill-seekers.”

“It may be that the third party tools already mentioned (pullmd and skill-seekers) make the process of adding URL/RSS items to source_documents much more straightforward.”

Honest verdict — HYBRID, with a strong lean toward INTEGRATE for specific adapters.

Skill-Seekers componentKH equivalentAdopt verdictRationale
SkillConverter base class + CONVERTER_REGISTRYKH has implicit per-path adapters; no central registry todayINSPIRATION for canonical pipeline Layer 3 (shape adapters). Don’t import Skill-Seekers’s class; mirror the architectural pattern.Already what 0.7-synthesis §2 recommends.
doc_scraper.py (BeautifulSoup + llms.txt + sitemap)lib/extraction/url.ts (Readability + jsdom)HYBRID — keep Readability for single-URL save; add Skill-Seekers’s pattern for bulk-docs-site ingest (a new use case)Readability is better for “I read this article”; doc_scraper is better for “ingest the whole vendor docs site at once”
pdf_scraper.py + pdf_extractor_poc.pylib/extraction/pdf.ts (unpdf)STRONG INTEGRATE for v2 — replaces or wraps unpdf with chapter detection + OCR + image extraction. Defer to v2 because dependency footprint shift (pdfplumber + Pillow + Tesseract) is non-trivial.KH’s unpdf is text-only — adequate for v1 ingest, limiting for long-form structured PDFs
word_scraper.pylib/bid-library-ingest/docx-to-markdown.ts (mammoth + Turndown)PARTIAL ADOPT — same toolchain (mammoth + python-docx); Skill-Seekers’s metadata-extraction pattern (subject, title, keywords) is something KH should add.KH already uses mammoth; just add metadata extraction. ~3-4 hours effort.
MarkdownCleanerlib/extraction/clean-mdx-tags.ts (MDX-tag stripping)ADOPT cleanup helpers (remove_html_tags, extract_first_section).Composes downstream of mammoth → Turndown; not a replacement. ~1-2h port.
RAGChunkerlib/content/chunking.ts (heading-based)DON’T REPLACE. Optionally adopt token-budget chunking as a SECOND mode (gate on chunkingMode param) for headingless corpora.Heading-based is correct for KH’s Q&A-dominant corpus. Token-budget is correct for headingless PDFs. Both are valuable; ship both. ~150 LOC addition. Medium priority post-canonical pipeline.
embedding_pipeline.py (cache + cost tracking + multi-provider)lib/ai/embed.ts (OpenAI-only, in-memory LRU cache)CONSIDER cost-tracking and disk-cache patterns; multi-provider is unnecessary (KH is committed to text-embedding-3-large).KH’s in-memory cache is fine for hot embeds; disk cache would help bulk re-ingest. Cost tracking would inform spend decisions. ~1 day port. Low priority.
code_analyzer.py + dependency_analyzer.py (9-language code analysis)n/a (KH doesn’t analyse code)NICHE ADOPT — useful as a third “build-not-wired-detector” alongside Knip + Graphify.Niche; Knip + Graphify already cover the dominant cases. ~1-2 days integration if pursued.
openapi_scraper.py (OpenAPI 2.0/3.0/3.1 → markdown)n/a (KH has no OpenAPI ingest)STRONG ADOPT — adds a new content type (api_specification) and unlocks API-driven workflows.New product capability. ~1 week effort. New shape='api-spec' adapter on canonical pipeline.
conflict_detector.py (docs-vs-code drift detection)n/aDON’T ADOPT — solves a different problem (library docs/code drift) not relevant to KH’s client-content-ingest use case.Not applicable.
unified_scraper.py + merge_sources.py (multi-source merging)n/aDON’T ADOPT — merging multiple sources into a single skill is an artefact of skill-generation, not KB ingest.Not applicable.
MCP server (40 tools across 7 categories)KH has its own MCP server with ~26 toolsDON’T REPLACE — KH’s MCP is bid-domain-specific. Skill-Seekers’s MCP is for skill-generation workflows.Different products.
Cloud storage adaptors (S3, Azure, GCP)KH uses Supabase Storage exclusivelyDON’T ADOPT — abstraction layer KH doesn’t need.Not applicable.
Git-source config publishing + marketplacen/aDON’T ADOPT — Skill-Seekers’s “configs in git, marketplace publishing” is for distributing skill configs to other Skill-Seekers users.Not applicable.
sync/ (poll for upstream doc changes)KH uses RSS poller for feed_articlesDON’T ADOPT — KH’s intelligence pipeline is tighter to RSS-with-relevance-gating.Not applicable.
workflows/ (50+ YAML enhancement presets)n/aDON’T ADOPT directly. Inspiration for KH’s skill enhancement workflows in lib/ai/skills/.Different abstraction layer.
storage/ cloud storage adaptorsSupabase StorageDON’T ADOPT — not needed.Not applicable.

2.9 Q9 — Scope-tag taxonomy (client feedback Item 3) — could Skill-Seekers’s metadata system handle it?

Section titled “2.9 Q9 — Scope-tag taxonomy (client feedback Item 3) — could Skill-Seekers’s metadata system handle it?”

Already addressed in §2.4 above. Short answer: NO. Skill-Seekers’s categories keyword-rule pattern is inspirational but insufficient. The right home is a KH-native scope_tag typed column + entity_relationships model, designed to support anti-tags and conflict surfacing — neither of which Skill-Seekers handles.

However, one Skill-Seekers pattern is directly useful: the categories config field as a keyword-rule tier of scope inference that runs before AI classification. KH could adopt:

# proposed taxonomy config
scope_tags:
internal-it:
keywords: [staff, laptop, office network, endpoint, BYOD, MDM]
anti-keywords: [production, customer-facing, hosted, infrastructure]
production-infrastructure:
keywords: [server, hosting, AWS, production, infra, deployment]
anti-keywords: [staff, laptop, office]
application-layer:
keywords: [LMS, AA, websites, code, application, software]
anti-keywords: [hardware, infrastructure, datacentre]
office-physical:
keywords: [office, premises, building, reception, Phew office]
data-centre-physical:
keywords: [Telehouse, Nimbus, datacentre, data centre, colocation]

Each content_item would receive scope_tag(s) via:

  1. Deterministic keyword-rule scan (cheap; runs at ingest).
  2. AI classification override (expensive; runs in classify pipeline if rule output is ambiguous or empty).
  3. Anti-keyword detection (cheap; fires conflict-flag).

This is a 0.5-1 day implementation if added to the classification pipeline. Recommended.


3.1 Skill-Seekers ships the canonical-pipeline shape KH wants

Section titled “3.1 Skill-Seekers ships the canonical-pipeline shape KH wants”

The single most valuable observation from this evaluation: Skill-Seekers has already implemented, in production at 13.4k-star scale, the exact 4-layer canonical-pipeline architecture that 0.7-synthesis §2 recommends KH adopt. Their layers:

Skill-Seekers LayerKH Layer 1-4 (per 0.7-synthesis §2)
cli/main.py + parsers/* (CLI dispatch + transport)Layer 1: TRANSPORT/AUTH
source_detector.py + unified_scraper.py source selectionLayer 2: INPUT-SHAPE ROUTER
17 *_scraper.py adapters in CONVERTER_REGISTRYLayer 3: SHAPE ADAPTERS
unified_skill_builder.py + downstream chunking + embedding + storageLayer 4: CANONICAL PIPELINE CORE

This is the strongest argument for studying Skill-Seekers’s architecture in depth, not for adopting any specific module wholesale. A KH engineer building canonical pipeline Phase A foundation should read:

  • src/skill_seekers/cli/skill_converter.py — base class + registry pattern (~150 LOC).
  • src/skill_seekers/cli/unified_scraper.py — top-level orchestrator that routes to per-shape adapter then merges (read for patterns, KH won’t merge).
  • src/skill_seekers/cli/quality_metrics.py — per-skill quality assessment with grade computation. Maps to KH’s quality_score.
  • src/skill_seekers/cli/streaming_ingest.py — memory-efficient batch processing with progress + resume. Maps to KH’s EP2 batch worker with cooperative-cancel.

Time investment: 2-3 hours of reading. ROI: validates KH’s canonical-pipeline approach against a working production reference.

3.2 The “Multi-source unified scraping” pattern unlocks a future KH capability

Section titled “3.2 The “Multi-source unified scraping” pattern unlocks a future KH capability”

Skill-Seekers’s unified_scraper.py accepts a config like:

{
"name": "react",
"sources": [
{ "type": "documentation", "base_url": "https://react.dev/", ... },
{ "type": "github", "repo": "facebook/react", ... }
],
"merge_mode": "claude-enhanced"
}

and produces a single skill that merges intelligence from multiple sources, with conflict detection between them.

For KH: this maps to a future capability where a single KB ingest job pulls from multiple sources at once. E.g., “ingest the LBBD CSP — pull the Word doc, the related PDFs, and the Confluence page they reference, merge into one content_item with source_documents lineage to all three”. This is not v1 territory, but it’s a pattern worth keeping in mind for the canonical-pipeline IngestRequest envelope shape.

The 0.7-synthesis IngestRequest envelope (§4.3) currently models a single shape per request:

type IngestRequest = {
shape: 'url' | 'document-binary' | 'document-text' | 'qa-docx' | 'rss-discovery';
url?: ...; binary?: ...; text?: ...; qa_docx?: ...; rss_discovery?: ...;
};

Future-proofing recommendation: consider a multi-source shape that wraps multiple sub-IngestRequests:

type IngestRequest = {
shape: '...' | 'multi-source';
multi_source?: {
sources: IngestRequest[]; // recursive
merge_strategy: 'concat' | 'rule-based' | 'ai-enhanced';
};
};

This is architectural foresight, not a v1 ask. But the canonical-pipeline foundation should be designed to not preclude this.

3.3 Skill-Seekers’s MCP server is NOT a model for KH’s MCP server

Section titled “3.3 Skill-Seekers’s MCP server is NOT a model for KH’s MCP server”

KH currently has ~26 MCP tools (per docs/generated/mcp-inventory.md). Skill-Seekers ships 40 tools across 7 categories:

CategoryTool count
Core9
Extended10
Config Sources5
Config Splitting2
Config Publishing1
Marketplace4
Vector DB4
Workflow5
Total40

This is more than KH’s MCP, and the categories are all skill-management workflow tools (publish a config to git, push a skill to a marketplace, export to Weaviate, etc.). They are completely irrelevant to KH’s bid-management domain.

Per Liam’s feedback in graphify-evaluation-feedback.md Section 5.2.B:

“We already need to evaluate our MCP tooling as there is a considerably large amount which isn’t ideal.”

Lesson from Skill-Seekers’s MCP: don’t chase tool count. Skill-Seekers has 40 tools because they need 40 surfaces to support a skill-publishing workflow. KH has 26 — and per Liam, that’s already too many for the bid-management domain. The evaluation of KH’s MCP surface should be done in isolation, not against Skill-Seekers’s count.

3.4 Skill-Seekers’s quality_metrics.py maps to KH’s quality_score

Section titled “3.4 Skill-Seekers’s quality_metrics.py maps to KH’s quality_score”

Skill-Seekers’s QualityAnalyzer (per cli/quality_metrics.py):

@dataclass
class QualityScore:
total_score: float # 0-100
completeness: float # 0-100
accuracy: float # 0-100
coverage: float # 0-100
health: float # 0-100
grade: str # A+, A, A-, B+, B, B-, C+, C, C-, D, F (11 grades)

vs KH’s content_items.quality_score (text type, NULL until Phase D ai_call_log lands; computed by cron job via lib/quality/quality-score.ts).

Skill-Seekers’s model is stronger:

  • 4 sub-scores (completeness, accuracy, coverage, health), not just a single composite.
  • Grade letter alongside numeric score.
  • Per-metric severity (info/warning/error/critical).
  • Recommendations attached.

KH adoption recommendation:

ActionEffortPriority
Promote KH’s quality_score from text to numeric (or JSONB with sub-scores)~2h migration + types regenMedium — depends on whether stakeholders want the multi-axis view
Add a quality_grade derived column with A+/A/B+ etc.~1hLow — visual sugar
Add quality_recommendations text[] for actionable remediation~3hMedium — useful for the metadata-sidebar.tsx warning surface

This is an independent feature improvement from canonical-pipeline; could land in Stream 1.

3.5 Skill-Seekers’s streaming_ingest.py validates KH’s EP2 architecture

Section titled “3.5 Skill-Seekers’s streaming_ingest.py validates KH’s EP2 architecture”

Skill-Seekers ships a StreamingIngester with:

  • chunk_size, chunk_overlap, batch_size, max_memory_mb parameters.
  • IngestionProgress dataclass: progress_percent, chunks_per_second, eta_seconds.
  • Resume capability via checkpointing.

This is exactly the shape of KH’s EP2 markdown-orchestrator.ts worker:

  • Per-file progress tracking via pipeline_runs metadata JSON.
  • Cooperative-cancel via pipeline_runs.status polling.
  • Idempotency via fileSetHash.

Validation: the EP2 design is right. Skill-Seekers’s open-source implementation of the same pattern at scale confirms this is the canonical approach to long-running batch ingest. No work needed; this is a “we are on the right track” signal.


4. Specific recommendation per parent-session feedback bullet

Section titled “4. Specific recommendation per parent-session feedback bullet”

4.1 “Bias toward re-use of battle-tested infrastructure”

Section titled “4.1 “Bias toward re-use of battle-tested infrastructure””

My honest read: Skill-Seekers IS battle-tested at scale (13.4k stars; v3.5.0; 40 MCP tools; 17 source adapters). But “battle-tested” needs qualification:

  • Battle-tested for skill generation — yes, demonstrably.
  • Battle-tested for KB / RAG retrieval workflows — only at the chunking / embedding-export layer (the rest is skill-generation-specific).
  • Battle-tested for multi-tenant content management — no. Skill-Seekers is single-tenant by design.
  • Battle-tested for Q&A pair extraction from DOCX tables — no. KH’s extractQaPairs() is more sophisticated.

Where re-use is the right call:

  • openapi_scraper.pyre-use directly. New capability KH lacks; well-designed; specific to a clear input shape.
  • pdf_scraper.pyre-use via wrapper for v2. Adds OCR + chapter detection + image extraction.
  • MarkdownCleaner cleanup helpers — re-use as inspiration. Port the 2 useful methods to TS.
  • code_analyzer.py + dependency_analyzer.pyre-use as supplement to Knip/Graphify for cross-language audits.

Where re-use is the WRONG call:

  • RAGChunker — KH’s heading-based chunker is better for KH’s dominant content shape (Q&A pairs).
  • conflict_detector.py — solves a different problem (library docs/code drift, not scope-tagging).
  • MCP server — different product domain.
  • unified_scraper.py merge logic — different product (skill-merge ≠ KB-merge).
  • Cloud storage adaptors — KH uses Supabase Storage exclusively.

4.2 “What should we be doing” not “what’s lowest disruption”

Section titled “4.2 “What should we be doing” not “what’s lowest disruption””

My honest read: the right answer for KH is adopt Skill-Seekers’s architectural patterns (canonical pipeline shape, registry-based shape adapters, per-shape adapter modularity) and selected modules (openapi_scraper, pdf_scraper-for-v2, MarkdownCleaner cleanup, dependency_analyzer-as-supplement), but NOT adopt the parts that conflict with KH’s existing strong design (heading-based chunking, Supabase pgvector, Q&A docx parser, RSS+relevance pipeline, MCP for bid management).

The “what we should be doing” framing pushes toward: redesign canonical pipeline Phase A with the SkillConverter/CONVERTER_REGISTRY pattern explicitly in mind. Don’t let “we can wait for v2” defer this. It’s the architectural foundation.

4.3 “Storage may not be required for any docs”

Section titled “4.3 “Storage may not be required for any docs””

Per Liam’s feedback in 07-synthesis-feedback.md §3.2:

“Do we need to store binaries? If all content is extracted to markdown anyway, and we have the file provenance (for audit purposes), could all content be saved as markdown in a DB column/table?”

Skill-Seekers’s answer: Skill-Seekers does NOT keep binary originals. It extracts everything to markdown + JSON metadata + references/*.md, then optionally uploads to a vector DB. The binary is consumed and discarded at extract time. The “file provenance” is captured in the extraction metadata only.

This is consistent with Liam’s hypothesis — binary storage is not architecturally required if (a) you preserve enough provenance metadata to identify the source, and (b) extraction is deterministic enough that re-running it on a refreshed binary would produce the same canonical markdown.

For KH: the “no markdown bucket” recommendation in 0.7-synthesis §3.2 is reinforced by Skill-Seekers’s architecture. The binary is the audit trail (filename + file_size + content_hash + uploaded_by + uploaded_at metadata in source_documents); the canonical content is markdown in content_items.content (and chunked in content_chunks). No bucket needed for v1.

The question “do we need to keep documents bucket for binaries at all?” has 2 plausible answers:

  1. Keep documents bucket for binaries (status quo): preserves UK-compliance-grade audit trail with the original DOCX/PDF for legal/redownload purposes.
  2. Drop documents bucket entirely: rely on source_documents.{filename, file_size, mime_type, content_hash} + extracted markdown as the audit trail. User who wants the original DOCX back uploads a fresh copy.

Skill-Seekers’s pattern strongly favours option 2. Liam’s framing (“we’re not a document repository — SharePoint/Notion fills that role”) aligns with option 2. 0.7-synthesis §3.2 should be revisited with this stronger framing. A v2 follow-up question: “is the documents bucket itself a candidate for retirement once source_documents typed columns + extracted markdown are reliable, with ?format=docx re-export covering the ‘I want my doc back’ use case?“

4.4 “Pullmd and skill-seekers may make adding URL/RSS items to source_documents more straightforward”

Section titled “4.4 “Pullmd and skill-seekers may make adding URL/RSS items to source_documents more straightforward””

Per the brief and §07-synthesis-feedback NEW7 (URLs → source_documents v1):

The 0.7.4-Q7 ratification (Liam: v1) means URL ingests should write a source_documents row capturing the rendered-then-converted state at ingest time.

Skill-Seekers contribution to this: the doc_scraper.py adapter explicitly produces a SOURCE_DOCUMENT-shaped output for every URL fetched:

  • source_url, source_domain (typed)
  • extracted_text (the cleaned markdown body)
  • extraction_metadata (extraction_method, page_count, word_count, og_metadata, llms_txt_metadata)
  • content_hash (MD5 of normalised content — Skill-Seekers uses sha256 by default but trivially configurable)

This is the exact SourceDocumentDescriptor shape proposed in 0.7.1 §4.3 — and Skill-Seekers’s adapter already produces it. Adopting Skill-Seekers’s doc_scraper.py patterns for URL ingest would make URL → source_documents straightforward, because the adapter naturally produces SDD-compatible output.

Concrete recommendation for canonical pipeline Phase A:

Build the SourceDocumentDescriptor schema and the URL adapter contract such that Skill-Seekers-style adapter output drops in directly. Even if KH’s URL adapter remains TS-only (Readability), the output shape should match what Skill-Seekers produces. Future versions can drop in Skill-Seekers’s doc_scraper.py for bulk-doc-site ingest without re-wiring the canonical core.


Bringing all the recommendations together, ordered by effort and value:

RecommendationEffortValuePriorityPhase
1. Adopt Skill-Seekers’s SourceDocumentDescriptor output shape for canonical pipeline URL adapter0h (architectural; just match the shape during Phase A)High — futureproofs URL adapter for bulk-docs-site ingestMust — canonical pipeline Phase AStream 2 Phase A
2. Add openapi shape adapter using openapi_scraper.py (port to TS or wrap Python via REST shim)~1 weekHigh — new content-type capabilityShould — post-canonicalStream 2 Phase H (new)
3. Adopt MarkdownCleaner cleanup helpers (port remove_html_tags + extract_first_section to TS)~1-2hLow-Medium — improves DOCX→MD output cleanlinessCould — pre-re-ingestStream 1
4. Add scope-tag taxonomy (client feedback Item 3) — KH-native, inspired by Skill-Seekers categories~1-2 weeksHigh — solves real client pain (LBBD CSP misclassification)Must — addresses client safety concernStream 1 + new WP-G
5. Wrap pdf_scraper.py for v2 to add OCR + chapter detection + image extraction~1 weekMedium — improves PDF ingest for long-form structured documentsCould — defer to v2v2
6. Adopt Skill-Seekers categories keyword-rule pre-classify pattern as a deterministic tier before AI classify~0.5-1 dayMedium — cheaper than always-AI-classify; improves precisionCould — efficiency improvementStream 1 candidate
7. Add token-budget chunking as a SECOND chunking mode in chunkByHeadings() (gated on chunkingMode param)~150 LOC, ~1 dayMedium — handles headingless corpora betterShould — post-canonicalStream 2 Phase B candidate
8. Adopt Skill-Seekers’s multi-axis quality_score model (completeness, accuracy, coverage, health)~1 day migration + types regenMedium — better signal than single text scoreCould — improves quality opsStream 2 candidate
9. Adopt Skill-Seekers’s dependency_analyzer.py as a third “build-not-wired-detector” alongside Knip + Graphify~1-2 days integrationLow-Medium — niche; Knip + Graphify already cover most casesCould — optional supplementStream 1 candidate
10. Adopt Skill-Seekers’s embedding cost-tracking + disk-cache patterns~1 day portLow — minor efficiency winCould — efficiency improvementv2
11. Future-proof IngestRequest envelope to support multi-source shape0h architecturalLow — futureproofing for v3+Should — design onlyStream 2 Phase A
12. Read Skill-Seekers’s skill_converter.py, unified_scraper.py, quality_metrics.py, streaming_ingest.py for canonical-pipeline-design inspiration~2-3 hours readingHigh — validates canonical pipeline architecture against working production referenceShould — pre-Phase APre-Stream 2

Total recommended adoption from Skill-Seekers: ~3-5 weeks of work, mostly in Stream 2 post-canonical.

0 hours blocking re-ingest readiness gate — this evaluation does not gate the existing Stream 1 work in 0.7-synthesis §5.1.


R1: Adopting pdf_scraper.py brings pdfplumber + Pillow + Tesseract dependency footprint

  • pdfplumber is a >1 year mature library, well-maintained.
  • Pillow (image extraction) is universal but adds binary deps.
  • Tesseract (OCR) is the operational risk — it requires a system-level binary, not just a pip install. On Vercel (KH’s deployment platform), this may not be possible without containerisation.
  • Mitigation: ship without OCR for v2 first (just chapter detection + image extraction); add Tesseract via Cloud Run if OCR is needed later.

R2: Skill-Seekers’s Python-only stack means TS integration adds runtime polyglot complexity

  • KH’s TS stack runs on Vercel (Node 22).
  • Skill-Seekers is Python.
  • Embedding the Python pipeline as a subprocess adds a runtime dependency, deployment complexity (Vercel doesn’t run Python easily; needs Cloud Run), and observability split (TS errors in Sentry, Python errors elsewhere).
  • Mitigation: for openapi_scraper.py, port to TS using swagger-parser npm package — eliminate the Python dep entirely. For pdf_scraper.py, Cloud Run is already a viable target (production-readiness track).

R3: 13.4k stars ≠ widely-deployed-in-production

  • High star count signals popularity, not stability or production deployments.
  • The README has been translated to 11 languages, suggesting strong marketing — but Skill-Seekers-as-a-product targets indie skill builders, not enterprise KB platforms.
  • Mitigation: treat Skill-Seekers as “high-quality reference implementation”, not “battle-tested production library”. Adopt patterns; vendor specific modules; don’t treat the whole tool as a runtime dependency.

R4: Skill-Seekers’s multi-source unified_scraper.py merge logic uses Claude API by default

  • merge_mode: 'claude-enhanced' means the merge step calls Claude. For KH’s per-tenant cost model, this could spike inference spend at ingest time.
  • Mitigation: if KH adopts unified-merge patterns, opt for merge_mode: 'rule-based' to keep deterministic. Or build KH-native merge logic on top of entity_relationships.

R5: Skill-Seekers’s CONVERTER_REGISTRY pattern relies on Python’s importlib dynamic dispatch — TS equivalent needs careful design

  • Skill-Seekers uses lazy module import to avoid loading all 17 adapters on every CLI invocation.
  • TS doesn’t have the same first-class lazy-import story (dynamic import() exists but is async).
  • Mitigation: TS canonical pipeline can use static Record<Shape, Adapter> map with eager-loaded adapters. Cold-start cost is small compared to the value of type safety.

R6: Per-shape adapter modularity could fragment KH’s single-source-of-truth for ingest

  • Skill-Seekers has 17 adapters and accepts that they each have different feature sets and bugs. Bug fixes in one adapter don’t propagate.
  • Mitigation: KH’s canonical pipeline Layer 4 (universal post-extraction) is what enforces single-source-of-truth. The adapter’s only job is to produce a normalised ExtractedContent + SourceDocumentDescriptor. If that contract is strict, fragmentation stays at the adapter, not the core.

R7: Skill-Seekers may have its own docs-vs-code drift

  • The Config Format Reference v3.2.0 dated 2026-03-15. The MCP Reference v3.5.0 dated 2026-04-09. Doc dates suggest active maintenance, but feature gaps may exist.
  • Mitigation: rely on source code as the truth, not docs.

R8: Workflow YAML preset library (50+ files) may be irrelevant noise

  • Most are for software-library skill enhancement (auth-strategies, migration-guide, etc.).
  • Mitigation: ignore the workflows entirely. They add no value to KH’s KB workflow.

IDQuestionWhy it matters
Q-SS1Should KH adopt the openapi shape adapter using Skill-Seekers’s openapi_scraper.py patterns, sized as a Stream 2 Phase H new work-package?New product capability (~1 week effort). Liam call.
Q-SS2Should the canonical pipeline IngestRequest envelope (0.7-synthesis §4.3) be future-proofed with a multi-source shape supporting recursive sub-sources?Architectural foresight; 0h cost during Phase A; potentially-significant future flexibility. Liam call.
Q-SS3Should the v1 documents bucket be retired entirely (per §4.3 above) — relying on source_documents typed columns + extracted markdown as the audit trail, with ?format=docx re-export for “I want my doc back” use cases?Major architectural shift from 0.7-synthesis §3.2. Aligns with Skill-Seekers’s pattern + Liam’s “we are not a document repository” framing. Liam call.
Q-SS4Should KH’s quality_score schema be widened to a multi-axis model (completeness, accuracy, coverage, health) with a derived grade letter?~1 day migration; better signal for ops. Liam call.
Q-SS5Should the scope-tag taxonomy (client feedback Item 3) ship in Stream 1 as a new WP-G work-package, sized 1-2 weeks?Solves real client pain (LBBD CSP misclassification). Independent of canonical pipeline. Liam call.
Q-SS6Should KH adopt token-budget chunking as a second mode in chunkByHeadings(), gated on a chunkingMode parameter?~150 LOC; medium-priority improvement post-canonical pipeline. Liam call.
Q-SS7Should KH evaluate pdf_scraper.py for v2 PDF upgrade (OCR + chapter detection + image extraction)?Adds capability; brings Pillow + Tesseract dependency. Defer to v2. Liam call.
Q-SS8Should KH’s MCP tooling audit (per Liam’s feedback) treat Skill-Seekers’s 40-tool MCP as a cautionary example?Tool-count discipline. No specific work-package needed. Architectural framing.

SectionConfidenceReason
§1 What skill-seekers is95%Direct repo inspection; module-by-module review
§2.1 Q1 Direct P4/P7/P9 replacement88%Side-by-side compared sources; verdict is conservative
§2.2 Q2 MarkdownCleaner replaces mammoth → turndown92%Read both implementations; clear architectural distinction
§2.3 Q3 RAGChunker replaces regenerateChunks90%Read both algorithms; verdict is principled
§2.4 Q4 Smart metadata + conflict detection — scope tag90%Skill-Seekers’s Conflict dataclass clearly different from scope-tag use case
§2.5 Q5 C3.x supplements 0.2.5 audit88%Mapped 6 specific 0.2.5 findings against Skill-Seekers capabilities
§2.6 Q6 API extraction92%OpenAPI adapter is clear high-value addition
§2.7 Q7 Vector DB pgvector95%Verified absence via repo tree search
§2.8 Q8 Re-use vs integrate vs reinvent87%Synthesised across 17 modules; verdict is hybrid
§2.9 Q9 Scope-tag taxonomy90%Echoed §2.4
§3 Cross-cutting findings85%Architectural patterns are clear; specific module ports less certain
§4 Per-feedback recommendations85%Tied directly to feedback bullets
§5 Effort matrix75%Effort estimates are ±50% typical for greenfield port work
§6 Risk register88%Standard risk patterns; mitigations well-trodden
Overall88%
  1. R1 Tesseract OCR runtime risk (75%) — Vercel deployment may block this entirely; Cloud Run is the realistic target.
  2. R2 Python ↔ TS polyglot complexity (80%) — practical but adds operational complexity.
  3. R3 13.4k stars ≠ production-tested (85%) — broad popularity doesn’t equal enterprise-grade reliability.
  4. §5 Effort estimates (75%) — typical for greenfield port estimates.
  5. Q-SS1 OpenAPI adapter port effort (70%) — TS port via swagger-parser is plausible but unverified at this depth.

For Liam’s Phase 0.8.5 decision:

  1. Skill-Seekers IS a high-value evaluation target — but for ARCHITECTURAL PATTERNS, not wholesale module adoption. The SkillConverter + CONVERTER_REGISTRY pattern validates the canonical-pipeline shape recommended in 0.7-synthesis §2. Read the source as design inspiration; vendor specific modules where they fit.

  2. Three modules are STRONG ADOPT candidates:

    • openapi_scraper.py — new content-type capability (api_specification); ~1 week port to TS or Python wrapper.
    • MarkdownCleaner cleanup helpers — small useful additions to KH’s extraction pipeline; ~1-2h port.
    • SourceDocumentDescriptor-compatible output shape — design-time architectural choice; 0h cost.
  3. Three modules are CONDITIONAL ADOPT (post-v1, dependency-permitting):

    • pdf_scraper.py for PDF v2 upgrade — gain OCR + chapter detection + image extraction. Defer to v2; risk is Tesseract dependency on Vercel.
    • code_analyzer.py + dependency_analyzer.py as build-not-wired supplement — niche; only if Knip + Graphify still leave gaps.
    • embedding_pipeline.py cost-tracking + disk-cache patterns — efficiency improvements; v2 candidate.
  4. Five modules are DON’T ADOPT:

    • RAGChunker — KH’s heading-based chunking is better for KH’s Q&A-dominant corpus. Optionally adopt token-budget chunking as a secondary mode for headingless corpora (~150 LOC).
    • conflict_detector.py — solves a different problem (library docs/code drift, not scope-tagging).
    • MCP server (40 tools) — different product domain; KH’s MCP is bid-management-specific.
    • Cloud storage adaptors (S3/Azure/GCP) — KH uses Supabase Storage exclusively.
    • Multi-source unified_scraper.py merge logic — different product (skill-merge ≠ KB-merge); KH-native merge via entity_relationships is the right approach.
  5. Skill-Seekers reinforces three architectural decisions in 0.7-synthesis:

    • No markdown bucket needed for v1 — Skill-Seekers extracts and discards binaries. Aligns with Liam’s “we are not a document repository” framing. Strengthens §3.2 recommendation.
    • URLs → source_documents v1 is straightforward — Skill-Seekers’s doc_scraper.py already produces the SDD-compatible output shape. Adoption removes the design risk on 0.7.4-Q7.
    • Canonical pipeline 4-layer architecture is correct — Skill-Seekers ships this exact shape in production. Validates 0.7-synthesis §2.
  6. Skill-Seekers does NOT solve the client’s scope-tag problem (feedback Item 3). A KH-native scope-tag taxonomy work-package (~1-2 weeks, Stream 1 candidate) is recommended. Skill-Seekers’s categories keyword-rule pattern is a useful inspiration but insufficient (no anti-tags, no conflict surfacing, no per-tenant scope).

  7. No work blocks Stream 1 re-ingest readiness gate. All Skill-Seekers adoption recommendations land in Stream 2 (canonical pipeline) or v2 (post-launch).

  8. The “what should we be doing” framing pushes toward: redesign canonical pipeline Phase A’s adapter contract with Skill-Seekers’s CONVERTER_REGISTRY pattern explicitly in mind. Don’t defer this to v2 — it’s the architectural foundation.


  • Repo: https://github.com/yusufkaraaslan/Skill_Seekers (default branch: development, NOT main)
  • Stars: 13,352 at time of evaluation
  • Language: Python 3.10+
  • Licence: MIT
  • Description: “Convert documentation websites, GitHub repositories, and PDFs into Claude AI skills with automatic conflict detection”

Core architecture:

  • src/skill_seekers/cli/skill_converter.py — base class + CONVERTER_REGISTRY pattern (~150 LOC)
  • src/skill_seekers/cli/unified_scraper.py — multi-source orchestrator + merger
  • src/skill_seekers/cli/main.py — CLI dispatch

Source adapters (17 total):

  • doc_scraper.py — DocToSkillConverter (web/HTML)
  • github_scraper.py — GitHubScraper (3-stream)
  • pdf_scraper.py + pdf_extractor_poc.py — PDFToSkillConverter
  • word_scraper.py — WordToSkillConverter (mammoth + python-docx)
  • epub_scraper.py — EpubToSkillConverter
  • video_scraper.py — VideoToSkillConverter (transcript)
  • codebase_scraper.py — CodebaseAnalyzer (9 languages)
  • jupyter_scraper.py — JupyterToSkillConverter
  • html_scraper.py — HtmlToSkillConverter (local HTML)
  • openapi_scraper.py — OpenAPIToSkillConverter (2.0/3.0/3.1)
  • asciidoc_scraper.py, pptx_scraper.py, rss_scraper.py, man_scraper.py, confluence_scraper.py, notion_scraper.py, chat_scraper.py

Core helpers:

  • markdown_cleaner.py — MarkdownCleaner (HTML stripping + section extraction)
  • rag_chunker.py — RAGChunker (token-budget + paragraph-boundary)
  • code_analyzer.py — 9-language signature extraction (AST/regex)
  • dependency_analyzer.py — import-graph + cycle detection (NetworkX)
  • quality_metrics.py — QualityAnalyzer with multi-axis scoring + grading
  • quality_checker.py — SkillQualityChecker for content validation
  • conflict_detector.py — ConflictDetector for docs-vs-code drift
  • embedding_pipeline.py — multi-provider + cache + cost tracking
  • streaming_ingest.py — StreamingIngester with progress + resume
  • api_reference_builder.py — markdown API reference generation
  • pattern_recognizer.py, architectural_pattern_detector.py, signal_flow_analyzer.py — pattern detection at 3 depths

MCP layer:

  • src/skill_seekers/mcp/server.py, server_fastmcp.py — MCP servers (stdio + HTTP)
  • src/skill_seekers/mcp/tools/ — 40 tool implementations

Storage:

  • src/skill_seekers/cli/storage/{s3,azure_storage,gcs_storage,base_storage}.py — cloud storage adaptors

Documentation:

  • docs/reference/CONFIG_FORMAT.md v3.2.0 (2026-03-15) — 17 source types specification
  • docs/reference/MCP_REFERENCE.md v3.5.0 (2026-04-09) — 40 MCP tools reference
  • docs/reference/SKILL_ARCHITECTURE.md — router/dispatcher pattern + 500-line guidance
  • docs/reference/C3_x_Router_Architecture.md — 3-stream codebase analysis architecture
  • docs/features/UNIFIED_SCRAPING.md — multi-source merging
  • docs/features/PATTERN_DETECTION.md — 10 design patterns across 9 languages
  • docs/features/PDF_CHUNKING.md — chapter detection + page chunking + code-block-merging
  • docs/features/PDF_ADVANCED_FEATURES.md, PDF_SCRAPER.md — PDF capabilities

Vector DB integrations:

  • docs/integrations/{CHROMA,FAISS,QDRANT,WEAVIATE}.md — 4 integration guides
  • examples/{chroma,faiss,qdrant,weaviate}-example/ — quickstart code per target
  • .github/workflows/{test-vector-dbs,vector-db-export}.yml — CI matrix

KH ingest+chunk infrastructure (compared against)

Section titled “KH ingest+chunk infrastructure (compared against)”

TS extract layer:

  • lib/ai/extract-content.ts (164 LOC) — extractStructuredContent() schema-based extraction via Claude
  • lib/ai/embed.ts (119 LOC) — OpenAI text-embedding-3-large, 1024 dims, in-memory LRU cache
  • lib/extraction/url.ts (128 LOC) — extractFromUrl() Readability/unpdf delegation
  • lib/extraction/html.ts (50 LOC) — extractFromHtml() Readability + jsdom
  • lib/extraction/pdf.ts (35 LOC) — extractPdfText() via unpdf
  • lib/extraction/turndown.ts (28 LOC) — Turndown + GFM plugin
  • lib/extraction/markdown-front-matter.ts (218 LOC) — hand-rolled YAML/TOML front-matter parser
  • lib/extraction/clean-mdx-tags.ts — MDX-tag stripping
  • lib/extraction/og-metadata.ts, markdown-title.ts, content-type-detect.ts, url-validation.ts

TS Q&A docx:

  • lib/bid-library-ingest/docx-to-markdown.ts (75 LOC) — mammoth + Turndown two-step
  • lib/bid-library-ingest/extract-qa-pairs.ts (498 LOC) — Pattern A/B/C table extractor
  • lib/bid-library-ingest/extract-answer.ts, resolve-question.ts

TS chunk + store:

  • lib/content/chunking.ts (220 LOC) — chunkByHeadings() heading-based chunker
  • lib/content/chunk-store.ts (203 LOC) — regenerateChunks() orchestrator

Python pipeline:

  • scripts/kb_pipeline/extract.py (417 LOC) — trafilatura + Jina + pdfplumber cascade
  • scripts/kb_pipeline/chunk.py (286 LOC) — Python mirror of chunkByHeadings
  • scripts/kb_pipeline/embed.py, classify.py, dedup.py, store.py, summarise.py, progressive_depth.py, pipeline.py
  • docs/plans/phase-0-investigation/0.7-synthesis.md — canonical pipeline architecture (4 layers)
  • docs/plans/phase-0-investigation/0.7.1-path-normalisation-feasibility.md — 10 paths → 5 kernels
  • docs/plans/phase-0-investigation/0.7.4-source-documents-history-relationship.md — versioning + 1:N model
  • docs/plans/phase-0-investigation/07-synthesis-feedback.md — Liam’s feedback (storage, scope tags, pre-existing infrastructure)
  • docs/plans/phase-0-investigation/graphify-evaluation-feedback.md — re-use vs integrate framing
  • docs/plans/phase-0-investigation/trpc-evaluation-feedback.md — pattern of “we have time to make architectural changes”
  • docs/plans/phase-0-investigation/kh-client-feedback.md — scope-tag taxonomy (Item 3); RAG retrieval (Item 2)

Audit complete. 88% overall confidence. 8 open questions surfaced for parent-session ratification (§7). 12 specific adoption recommendations sized in §5 effort matrix. Tooling delivers 3 strong-adopt + 3 conditional-adopt + 5 don’t-adopt verdicts (§9).