# AGENTS.md - Skill Seekers
Comprehensive reference for AI coding agents. Skill Seekers is a Python CLI tool (v3.6.0) that converts documentation sites, GitHub repos, PDFs, videos, notebooks, wikis, and more into AI-ready skills for 21+ LLM platforms and RAG pipelines.
## Project Overview
**Skill Seekers** is a universal preprocessing layer that transforms raw documentation and code into structured knowledge assets. It supports 17+ source types and exports to 21+ AI platforms including Claude, Gemini, OpenAI, LangChain, LlamaIndex, and various vector databases.
### Key Capabilities
- **Source Types (17):** Documentation websites, GitHub repos, PDFs, Word docs, EPUBs, videos, local codebases, Jupyter notebooks, HTML, OpenAPI specs, AsciiDoc, PowerPoint, Confluence, Notion, RSS feeds, man pages, chat exports
- **Export Targets (21):** Claude, Gemini, OpenAI, MiniMax, OpenCode, Kimi, DeepSeek, Qwen, OpenRouter, Together AI, Fireworks AI, Markdown, LangChain, LlamaIndex, Haystack, Weaviate, ChromaDB, FAISS, Qdrant, Pinecone
- **MCP Server:** FastMCP-based Model Context Protocol server for AI assistant integration
## Setup
```bash
# REQUIRED before running tests (src/ layout β tests hard-exit if package not installed)
pip install -e .
# With dev tools (pytest, ruff, mypy, coverage)
pip install -e ".[dev]"
# With specific LLM platform support
pip install -e ".[gemini]" # Google Gemini
pip install -e ".[openai]" # OpenAI ChatGPT
pip install -e ".[all-llms]" # All LLM platforms
# With all optional dependencies (except video-full)
pip install -e ".[all]"
# Full video processing (heavy dependencies)
pip install -e ".[video-full]"
```
Note: `tests/conftest.py` checks that `skill_seekers` is importable and calls `sys.exit(1)` if not. Always install in editable mode first.
### Environment Variables
Create a `.env` file or export these variables:
```bash
ANTHROPIC_API_KEY # For Claude AI enhancement
GOOGLE_API_KEY # For Gemini support
OPENAI_API_KEY # For OpenAI support
GITHUB_TOKEN # For GitHub repo scraping (higher rate limits)
```
## Build / Test / Lint
```bash
# Full suite (never skip β all must pass)
pytest tests/ -v
# Fast iteration (skip slow, integration, E2E, network, MCP)
pytest tests/ -m "not slow and not integration and not e2e and not network and not serial and not mcp_only" -q
# Fast parallel (install pytest-xdist first)
pytest tests/ -n auto --dist=loadfile -m "not slow and not integration and not e2e and not network and not serial and not mcp_only" -q
# 3-phase runner script (recommended for local dev)
bash scripts/run_tests_fast.sh
# Single test
pytest tests/test_scraper_features.py::test_detect_language -v
# Skip slow/integration
pytest tests/ -v -m "not slow and not integration"
# With coverage
pytest tests/ --cov=src/skill_seekers --cov-report=term
# Lint + format check (matches CI)
ruff check src/ tests/
ruff format --check src/ tests/
# Type check (non-blocking β mypy is continue-on-error in CI)
mypy src/skill_seekers --show-error-codes --pretty
```
**Pytest config:** `asyncio_mode = "auto"`, so `@pytest.mark.asyncio` is implicit. Test markers: `slow`, `integration`, `e2e`, `venv`, `bootstrap`, `benchmark`, `asyncio`, `serial`, `network`, `mcp_only`.
**CI note:** CI pins `ruff==0.15.8` (not the `>=0.14.13` dev dep). If formatting behaves differently locally, check the CI version.
**CI test phases:** Tests are split into 3 parallel jobs:
- `test-fast` β 3386 unit tests with xdist across OS/Python matrix
- `test-serial` β 69 serial/integration/E2E/network tests
- `test-mcp` β 193 MCP tests (requires `[mcp]` extras)
## Code Style
### Formatting Rules (ruff β from pyproject.toml)
- **Line length:** 100 characters
- **Target Python:** 3.10+
- **Enabled lint rules:** E, W, F, I, B, C4, UP, ARG, SIM
- **Ignored rules:** E501 (line length handled by formatter), F541 (f-string style), ARG002 (unused method args for interface compliance), B007 (intentional unused loop vars), I001 (formatter handles imports), SIM114 (readability preference)
### Imports
- Sort with isort (via ruff); `skill_seekers` is first-party
- Standard library β third-party β first-party, separated by blank lines
- Use `from __future__ import annotations` only if needed for forward refs
- Guard optional imports with try/except ImportError (see `adaptors/__init__.py` pattern):
```python
try:
from .claude import ClaudeAdaptor
from .minimax import MiniMaxAdaptor
except ImportError:
ClaudeAdaptor = None
MiniMaxAdaptor = None
```
### Naming Conventions
- **Files:** `snake_case.py` (e.g., `source_detector.py`, `config_validator.py`)
- **Classes:** `PascalCase` (e.g., `SkillAdaptor`, `ClaudeAdaptor`, `SourceDetector`)
- **Functions/methods:** `snake_case` (e.g., `get_adaptor()`, `detect_language()`)
- **Constants:** `UPPER_CASE` (e.g., `ADAPTORS`, `DEFAULT_CHUNK_TOKENS`, `VALID_SOURCE_TYPES`)
- **Private:** prefix with `_` (e.g., `_read_existing_content()`, `_validate_unified()`)
### Type Hints
- Gradual typing β add hints where practical, not enforced everywhere
- Use modern syntax: `str | None` not `Optional[str]`, `list[str]` not `List[str]`
- MyPy config: `disallow_untyped_defs = false`, `check_untyped_defs = true`, `ignore_missing_imports = true`
- Tests are excluded from strict type checking (`disallow_untyped_defs = false`, `check_untyped_defs = false` for `tests.*`)
### Docstrings
- Module-level docstring on every file (triple-quoted, describes purpose)
- Google-style docstrings for public functions/classes
- Include `Args:`, `Returns:`, `Raises:` sections where useful
### Error Handling
- Use specific exceptions, never bare `except:`
- Provide helpful error messages with context
- Use `raise ValueError(...)` for invalid arguments, `raise RuntimeError(...)` for state errors
- Guard optional dependency imports with try/except and give clear install instructions on failure
- Chain exceptions with `raise ... from e` when wrapping
### Suppressing Lint Warnings
- Use inline `# noqa: XXXX` comments (e.g., `# noqa: F401` for re-exports, `# noqa: ARG001` for required but unused params)
## Project Layout
```
src/skill_seekers/ # Main package (src/ layout)
cli/ # CLI commands and entry points (100+ files)
adaptors/ # Platform adaptors (Strategy pattern, inherit SkillAdaptor)
arguments/ # CLI argument definitions (one per source type)
parsers/ # Subcommand parsers (one per source type)
storage/ # Cloud storage (inherit BaseStorageAdaptor)
main.py # Unified CLI entry point (COMMAND_MODULES dict)
source_detector.py # Auto-detects source type from user input
create_command.py # Unified `create` command routing
config_validator.py # VALID_SOURCE_TYPES set + per-type validation
unified_scraper.py # Multi-source orchestrator (scraped_data + dispatch)
unified_skill_builder.py # Pairwise synthesis + generic merge
mcp/ # MCP server (FastMCP + legacy)
tools/ # MCP tool implementations by category (10 files)
server_fastmcp.py # FastMCP server implementation
server_legacy.py # Legacy MCP server
sync/ # Sync monitoring (Pydantic models)
benchmark/ # Benchmarking framework
embedding/ # FastAPI embedding server
workflows/ # 67 YAML workflow presets
_version.py # Reads version from pyproject.toml
tests/ # 160 test files (pytest)
test_adaptors/ # 22 adaptor-specific test files
conftest.py # Test configuration with package check
configs/ # Preset JSON scraping configs
docs/ # Documentation (guides, integrations, architecture)
```
## Key Patterns
**Adaptor (Strategy) pattern** β all platform logic in `cli/adaptors/`. Inherit `SkillAdaptor`, implement `format_skill_md()`, `package()`, `upload()`. Register in `adaptors/__init__.py` ADAPTORS dict.
**Scraper pattern** β each source type has: `cli/<type>_scraper.py` (with `<Type>ToSkillConverter` class + `main()`), `arguments/<type>.py`, `parsers/<type>_parser.py`. Register in `parsers/__init__.py` PARSERS list, `main.py` COMMAND_MODULES dict, `config_validator.py` VALID_SOURCE_TYPES set.
**Unified pipeline** β `unified_scraper.py` dispatches to per-type `_scrape_<type>()` methods. `unified_skill_builder.py` uses pairwise synthesis for docs+github+pdf combos and `_generic_merge()` for all other combinations.
**MCP tools** β grouped in `mcp/tools/` by category. `scrape_generic_tool` handles all new source types.
**CLI subcommands** β git-style in `cli/main.py`. Each delegates to a module's `main()` function.
**Supported source types (17):** documentation (web), github, pdf, local, word, video, epub, jupyter, html, openapi, asciidoc, pptx, confluence, notion, rss, manpage, chat. Each detected automatically by `source_detector.py`.
**Supported platforms (21):** claude, gemini, openai, minimax, opencode, kimi, deepseek, qwen, openrouter, together, fireworks, markdown, langchain, llama-index, haystack, weaviate, chroma, faiss, qdrant, pinecone.
## CLI Commands
```bash
# Core commands
skill-seekers create <source> # Create skill from any source (auto-detects type)
skill-seekers scan <dir> # AI-detect a project's tech stack and emit per-framework configs
skill-seekers enhance <directory> # AI-powered enhancement
skill-seekers package <directory> # Package skill for target platform
skill-seekers upload <file> # Upload skill to target platform
skill-seekers install <source> # One-command workflow (scrape + enhance + package + upload)
# Utilities
skill-seekers estimate <source> # Estimate page count before scraping
skill-seekers doctor # Health check for dependencies
skill-seekers config # Configure API keys and settings
skill-seekers workflows # List and apply workflow presets
skill-seekers resume <job_id> # Resume interrupted scraping
# Advanced
skill-seekers stream <source> # Streaming ingestion
skill-seekers update <directory> # Incremental update
skill-seekers multilang <directory> # Multi-language support
```
## Testing Instructions
### Test Structure
- Unit tests: `tests/test_*.py` β test individual modules
- Adaptor tests: `tests/test_adaptors/test_*_adaptor.py` β test platform adaptors
- E2E tests: `tests/test_*_e2e.py` β end-to-end integration tests
### Running Tests
```bash
# Fast test run (skip slow/integration tests)
pytest tests/ -v -m "not slow and not integration"
# Full test suite
pytest tests/ -v
# With coverage report
pytest tests/ --cov=src/skill_seekers --cov-report=term-missing
# Specific test categories
pytest tests/ -v -m "slow" # Only slow tests
pytest tests/ -v -m "integration" # Only integration tests
pytest tests/ -v -m "e2e" # Only E2E tests
```
### Test Fixtures
Test fixtures are located in `tests/fixtures/` and include sample configs, HTML files, and mock data.
## Git Workflow
- **`main`** β production, protected
- **`development`** β default PR target, active dev
- Feature branches created from `development`
## Pre-commit Checklist
```bash
ruff check src/ tests/
ruff format --check src/ tests/
pytest tests/ -v -x # stop on first failure
```
Never commit API keys. Use env vars: `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY`, `OPENAI_API_KEY`, `GITHUB_TOKEN`.
## CI/CD
GitHub Actions (7 workflows in `.github/workflows/`):
- **tests.yml** β ruff + mypy lint job, then pytest matrix (Ubuntu + macOS, Python 3.10-3.12) with Codecov upload
- **release.yml** β tag-triggered: tests β version verification β PyPI publish via `uv build`
- **test-vector-dbs.yml** β tests vector DB adaptors (weaviate, chroma, faiss, qdrant)
- **docker-publish.yml** β multi-platform Docker builds (amd64, arm64) for CLI + MCP images
- **quality-metrics.yml** β quality analysis with configurable threshold
- **scheduled-updates.yml** β weekly skill updates for popular frameworks
- **vector-db-export.yml** β weekly vector DB exports
## Deployment
### Docker
Multi-stage Dockerfile with Python 3.12 slim base:
```bash
# Build CLI image
docker build -t skill-seekers:local -f Dockerfile .
# Run CLI
docker run -v $(pwd)/output:/output skill-seekers:local create https://docs.example.com
# Run MCP server
docker build -t skill-seekers-mcp:local -f Dockerfile.mcp .
docker run -p 8765:8765 skill-seekers-mcp:local
```
### MCP Server
The MCP server provides Model Context Protocol integration:
```bash
# Start FastMCP server
skill-seekers-mcp
# Or use the Python module
python -m skill_seekers.mcp.server_fastmcp
```
## Security Considerations
- **API Keys:** Never commit API keys to version control. Use environment variables or `.env` files (already in `.gitignore`)
- **Docker:** Runs as non-root user (`skillseeker`, UID 1000)
- **Dependencies:** Regular security updates via `pip audit` or `safety check`
- **Sandboxing:** Video processing uses optional dependencies that can be heavy; install `[video-full]` only when needed
## Additional Resources
- **Website:** https://skillseekersweb.com/
- **Documentation:** https://skillseekersweb.com/
- **PyPI:** https://pypi.org/project/skill-seekers/
- **Repository:** https://github.com/yusufkaraaslan/Skill_Seekers
- **Config Browser:** https://skillseekersweb.com/
- **Project Board:** https://github.com/users/yusufkaraaslan/projects/2
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
**Skill Seekers** converts documentation from 18 source types into production-ready formats for 21+ AI platforms (LLM platforms, RAG frameworks, vector databases, AI coding assistants). Published on PyPI as `skill-seekers`.
**Version:** 3.9.0 (dev; last release 3.8.0) β source of truth is `src/skill_seekers/_version.py` | **Python:** 3.10+ | **Website:** https://skillseekersweb.com/
**Architecture:** See `docs/UML_ARCHITECTURE.md` for UML diagrams and module overview. StarUML project at `docs/UML/skill_seekers.mdj`. Refactor state/history: `docs/UNIFICATION_PLAN.md` (Grand Unification β all 5 phases done; remaining cosmetic items listed there).
## Essential Commands
```bash
# REQUIRED before running tests or CLI (src/ layout)
pip install -e .
# Run all tests (NEVER skip - all must pass before commits)
pytest tests/ -v
# Fast iteration (skip slow MCP tests ~20min)
pytest tests/ --ignore=tests/test_mcp_fastmcp.py --ignore=tests/test_mcp_server.py --ignore=tests/test_install_skill_e2e.py -q
# Single test
pytest tests/test_scraper_features.py::test_detect_language -vv -s
# Code quality (must pass before push - matches CI)
uvx ruff check src/ tests/
uvx ruff format --check src/ tests/
mypy src/skill_seekers # continue-on-error in CI
# Auto-fix lint/format issues
uvx ruff check --fix --unsafe-fixes src/ tests/
uvx ruff format src/ tests/
# Build & publish
uv build
uv publish
```
## CI Matrix
Runs on push/PR to `main` or `development`. Lint job (Python 3.12, Ubuntu) + Test job (Ubuntu + macOS, Python 3.10/3.11/3.12, excludes macOS+3.10). Both must pass for merge.
## Git Workflow
- **Main branch:** `main` (requires tests + 1 review)
- **Development branch:** `development` (default PR target, requires tests)
- **Feature branches:** `feature/{task-id}-{description}` from `development`
- PRs always target `development`, never `main` directly
## Architecture
### CLI: Unified create command
Entry point `src/skill_seekers/cli/main.py`. The `create` command is the **primary** entry point for skill creation β it auto-detects source type and routes to the appropriate `SkillConverter`. The `scan` command (added in #327) is a separate discovery step for projects with multiple frameworks; it emits one config file per detected framework and you then run `create` on each.
```
skill-seekers create <source> # Auto-detect: URL, owner/repo, ./path, file.pdf, etc.
skill-seekers scan <dir> # AI-driven discovery β emits one config per detected framework + <project>-codebase.json
skill-seekers package <dir> # Package for platform (--target claude/gemini/openai/markdown/minimax/opencode/kimi/deepseek/qwen/openrouter/together/fireworks/atlas/langchain/llama-index/haystack/chroma/faiss/weaviate/qdrant/pinecone/ibm-bob)
```
### Scan command (issue #327)
`skill-seekers scan <dir>` is an AI-driven project knowledge-base bootstrapper. Pipeline in `src/skill_seekers/cli/scan_command.py`:
1. `collect_signals()` in `signal_collectors.py` β deterministic, bounded gathering of manifests + README + Dockerfile/CI + sampled source files + git remote. **Per-kind byte budgets** (24 KB manifest / 6 KB README / 6 KB CI / 28 KB samples, total 64 KB) so a fat package.json can't crowd out other kinds. `_SOURCE_DIRS` covers ~14 layouts (Go `cmd/`, Rust `crates/`, JS monorepo `apps/packages/`, Maven `source/`, Django at root); also walks root one level deep for flat-layout Python.
2. `detect_with_ai(bundle, AgentClient)` β one LLM call, structured JSON output. **Source signals are first-2-KB of each file** (whole-file sampling, no regex parsing β added in WS4 because regex missed Go multi-line imports + Rust `mod`/`extern crate`). Canonical-slug prompt + the canonical-name resolver are coupled β change one, update the other.
3. `resolve_or_generate_with_status()` β for each detection: try `out_dir/<slug>.json` (cache from prior run), then `resolve_config_path` from `config_fetcher` with multiple canonical name candidates (`_canonical_name_candidates` handles `"Godot Engine"` β `"godot"`, plus CJK / European suffixes like `"Godot εΌζ"`, `"React γγ¬γΌγ γ―γΌγ―"`, `"Lodash Bibliothek"`), then `generate_config_with_ai` as the last resort. Always appends `.json` to lookup names so local-disk and user-dir resolution actually finds files. Always stamps `metadata.detected_version` (nested, not top-level β `metadata.version` already exists and means config-schema version).
4. `emit_codebase_config()` β always writes `<project>-codebase.json` (a `type: local` source pointed at the project root).
5. `diff_against_existing()` β keyed by **filename slug** (not internal `data["name"]`) so re-scans don't churn when the AI returns a display name vs the registry canonical slug.
6. `_archive_removed()` β when a config disappears from detections, MOVE (not delete β user may have hand-edited) to `out_dir/.archived/<UTC-timestamp>/`. Runs after diff, before fresh writes.
7. `maybe_publish()` β **native async** (WS11). Opt-in submission of freshly AI-generated configs to the community registry. Pre-checks `GITHUB_TOKEN`. Idempotency guard: `_find_existing_issue` queries GitHub Search API for an existing open issue with the same config name before submitting. Retries transient failures (rate limit, 5xx) with 0s/5s/15s backoff. `_prompt_async` wraps `input()` via `asyncio.to_thread` so the event loop isn't blocked.
**CLI dispatch** uses the `COMMAND_CLASSES` table in `main.py` (added in WS1). `scan` and `doctor` are dispatched as `Cls(args).execute()` consuming the parsed argparse namespace directly β no `_reconstruct_argv` hack, no duplicate argparse. `ScanCommand.execute()` is the single `asyncio.run` boundary wrapping `run_scan` (sync) + `maybe_publish` (async). Remaining ~14 commands still use the legacy `COMMAND_MODULES` dispatch; they're flagged for migration.
**Cost guardrails**: `--max-ai-generations N` (default 10) caps unbounded AI generation; `--dry-run` previews without writing or invoking AI; `--probe-urls` HEAD-checks AI-generated URLs with retry-on-404 and stamps `metadata._url_unverified` on confirmed-bad URLs.
**Safety**: All writes use `_atomic_write_json` (`os.replace` after writing to `.tmp`) so a `KeyboardInterrupt` mid-write can't corrupt configs. `_safe_size` guards `stat()` so broken symlinks don't crash the scan. `ScanCommand.execute` calls `logging.basicConfig` so `logger.warning`/`error` is visible; exit code is non-zero when no configs and no codebase config were emitted.
**Public constant**: `SourceDetector.CODE_PROJECT_MARKERS` (was `_CODE_PROJECT_MARKERS`) β shared between source_detector + signal_collectors. ~50 manifest types now (Pipfile, environment.yml, deno.json, flake.nix, Chart.yaml, deps.edn, dune-project, BUILD.bazel, β¦). Public so cross-module access doesn't reach into a private attribute.
### SkillConverter Pattern (Template Method + Factory)
All 18 source types implement the `SkillConverter` base class (`skill_converter.py`):
```python
converter = get_converter("web", config) # Factory lookup
converter.run() # Template: extract() β build_skill()
```
Registry in `CONVERTER_REGISTRY` maps source type β (module, class). `create_command.py` builds config from `ExecutionContext`, calls `get_converter()`, then runs centralized enhancement. `get_converter("config", {...})` constructs `UnifiedScraper` from the same factory-shaped dict (no special cases in create_command/MCP). The base resolves `skill_dir` once (strips trailing separators) and derives `data_file` via `data_file_for()` β subclasses must not re-derive paths.
### DocumentSkillBuilder (build side of 9 document scrapers)
`cli/document_skill_builder.py:DocumentSkillBuilder` sits between `SkillConverter` and the 9 document scrapers (epub, word, pptx, html, pdf, jupyter, man, rss, chat). It owns `categorize_content`, reference-file writing (tables, truncation, image guard), `index.md` + `SKILL.md` generation, and `load_extracted_data`. Variation points are class attrs (`DOC_NOUN`, `SOURCE_LABEL`, `LOAD_TOTAL_KEY`, `PATTERN_KEYWORDS`, `RANGE_LABEL`, β¦) and small hook methods (`category_stem`, `_write_reference_section`, `_write_skill_md_metadata`). Output is pinned **byte-identical** by golden trees in `tests/golden/phase2/` β `UPDATE_GOLDENS=1` rewrites them, only do that deliberately. Surviving full-method overrides are domain-shaped and commented per scraper.
### UnifiedScraper (multi-source configs)
`unified_scraper.py` dispatches via the class-level `SOURCE_DISPATCH` table; `_scrape_with_converter()` is the shared engine for the 13 mechanical source types (`get_converter()` + public `converter.extract()` + cache copy + sub-skill build), so **new types registered in `CONVERTER_REGISTRY` work in unified configs automatically**. documentation/github/local stay bespoke (commented why). `run()` deliberately does NOT follow the base template (TestRunOrchestration pins that run() triggers workflows).
### Data Flow (5 phases)
1. **Scrape** - Source-specific scraper extracts content to `output/{name}_data/pages/*.json`
2. **Build** - `build_skill()` categorizes pages, extracts patterns, generates `output/{name}/SKILL.md`
3. **Enhance** (optional) - LLM rewrites SKILL.md (`--enhance-level 0-3`, auto-detects API vs LOCAL mode)
4. **Package** - Platform adaptor formats output (`.zip`, `.tar.gz`, JSON, vector index)
5. **Upload** (optional) - Platform API upload
### Platform Adaptor Pattern (Strategy + Factory)
Factory: `get_adaptor(platform, config)` in `adaptors/__init__.py` returns a `SkillAdaptor` instance. Base class `SkillAdaptor` + `SkillMetadata` in `adaptors/base.py`.
```
src/skill_seekers/cli/adaptors/
βββ __init__.py # Factory: get_adaptor(platform, config), ADAPTORS registry
βββ base.py # Abstract base: SkillAdaptor, SkillMetadata
βββ openai_compatible.py # Shared base for OpenAI-compatible platforms
βββ claude.py # --target claude
βββ gemini.py # --target gemini
βββ openai.py # --target openai
βββ markdown.py # --target markdown
βββ minimax.py # --target minimax
βββ opencode.py # --target opencode
βββ kimi.py # --target kimi
βββ deepseek.py # --target deepseek
βββ qwen.py # --target qwen
βββ openrouter.py # --target openrouter
βββ together.py # --target together
βββ fireworks.py # --target fireworks
βββ langchain.py # --target langchain
βββ llama_index.py # --target llama-index
βββ haystack.py # --target haystack
βββ chroma.py # --target chroma
βββ faiss_helpers.py # --target faiss
βββ qdrant.py # --target qdrant
βββ weaviate.py # --target weaviate
βββ pinecone_adaptor.py # --target pinecone
βββ streaming_adaptor.py # --target streaming
```
All adaptors use `--target`. All adaptors are imported with `try/except ImportError` so missing optional deps don't break the registry.
### 18 Source Type Converters
Each in `src/skill_seekers/cli/{type}_scraper.py` as a `SkillConverter` subclass (no `main()`). The `create_command.py` uses `source_detector.py` to auto-detect, then calls `get_converter()`. Converters: web (doc_scraper), github, pdf, word, epub, video, local (codebase_scraper), jupyter, html, openapi, asciidoc, pptx, rss, manpage, confluence, notion, chat, config (unified_scraper).
### CLI Argument System (single-definition parsers)
```
src/skill_seekers/cli/
βββ parsers/ # Central SubcommandParser classes β the ONLY definition of each command's flags
β βββ create_parser.py # Progressive help disclosure (--help-web, --help-github, etc.)
βββ arguments/ # Argument definitions
β βββ common.py # add_all_standard_arguments() - shared across all scrapers
β βββ create.py # UNIVERSAL_ARGUMENTS, WEB_ARGUMENTS, GITHUB_ARGUMENTS, etc.
βββ exit_codes.py # EXIT_SUCCESS/ERROR/VALIDATION/INTERRUPT
βββ source_detector.py # Auto-detect source type from input string
```
Command modules' standalone `main(args=None)` paths build their parser FROM the central `SubcommandParser` class β **add/change a flag in `parsers/*.py` only**. Drift guards (`tests/test_cli_parsers.py::TestCentralModuleParserSync` and `TestCentralParserSingleSource`) fail CI on any divergence of dests/defaults/option strings.
`ExecutionContext.override()` is context-local (a `ContextVar` layered over the unchanged base singleton) β thread/async safe for the MCP server; propagate to worker threads via `copy_context`.
### Standalone subsystems (outside `cli/`)
Four top-level packages sit beside `cli/` and are largely independent of the scrapeβbuildβpackage flow:
- `embedding/` β FastAPI embedding-generation server (`python -m skill_seekers.embedding.server`) with a caching layer (`cache.py`) and multi-backend generators (OpenAI, sentence-transformers, Anthropic). Feeds the vector-DB adaptors.
- `sync/` β real-time doc-sync system: `detector.py` (content-hash / last-modified change detection), `monitor.py` (scheduled incremental re-scrapes), `notifier.py` (email/Slack/webhook). Keeps generated skills fresh as upstream docs change.
- `benchmark/` β performance suite (`runner.py`, `framework.py`) measuring scrape/embedding/storage/e2e timing, memory, and CPU; emits comparison + optimization reports.
- `workflows/` β bundled default enhancement-workflow presets consumed by the enhancement step.
### C3.x Codebase Analysis Pipeline
Local codebase analysis features, all opt-out (`--skip-*` flags):
- C3.1 `pattern_recognizer.py` - Design pattern detection (10 GoF patterns, 9 languages)
- C3.2 `test_example_extractor.py` - Usage examples from tests
- C3.3 `how_to_guide_builder.py` - AI-enhanced educational guides
- C3.4 `config_extractor.py` - Configuration pattern extraction
- C3.5 `generate_router.py` - Architecture overview generation
- C3.10 `signal_flow_analyzer.py` - Godot signal flow analysis
### MCP Server
`src/skill_seekers/mcp/server_fastmcp.py` - 40 tools via FastMCP. Transport: stdio (Claude Code) or HTTP (Cursor/Windsurf). Optional dependency: `pip install -e ".[mcp]"`
- **Tools run in-process** via `run_cli_main()` in `mcp/tools/_common.py`: same argv parsed by the command's REAL parser (sys.argv patch under a lock), stdout/stderr capture + contextvar log capture, identical `(stdout, stderr, returncode)` contract. No subprocess startup; old hard timeouts are advisory.
- **Exceptions BY DESIGN**: `enhance_skill` (LOCAL agent) and `install_skill`'s enhancement step stay subprocess β the agent must be a real child process for the fork-bomb-guard env semantics (`SKILL_SEEKER_ENHANCE_ACTIVE`). Never make these in-process.
- **Domain logic lives in `skill_seekers.services/`** (marketplace_manager, marketplace_publisher, config_publisher, source_manager, git_repo) β importable by CLI without the `[mcp]` extra; old `skill_seekers.mcp.*` paths are back-compat shims. No `sys.path` hacks anywhere in `mcp/`.
### Enhancement (AgentClient is the single AI transport)
Every AI call goes through `AgentClient` (`src/skill_seekers/cli/agent_client.py`): central truncation gate, timeout policy, error classification. `API_PROVIDERS` (provider registry) and `AGENT_PRESETS` (local-agent command templates) live ONLY there. Each `API_PROVIDERS` entry declares its wire `protocol` (`anthropic`/`openai`/`google`) and `supports_images` capability β `_call_api` branches on the resolved protocol, NOT the provider name, so an OpenAI/Anthropic-compatible provider needs no new branch. Adaptors declare provider/endpoint/model/prompt and route through `SkillAdaptor._enhance_skill_md_via_client` (atomic save with backup). Multimodal image input goes through `AgentClient.call_with_image()` (used by `video_visual` frame OCR across all image-capable providers); it no longer bypasses AgentClient with a direct SDK call.
- **API mode** (if API key set): Anthropic, Google Gemini, OpenAI, Moonshot/Kimi, MiniMax β detected in registry order; `SKILL_SEEKER_PROVIDER` forces one. Models: `SKILL_SEEKER_MODEL` (global) or `ANTHROPIC_MODEL`/`GOOGLE_MODEL`/`OPENAI_MODEL`/`MOONSHOT_MODEL`/`MINIMAX_MODEL`; `ANTHROPIC_BASE_URL` for compatible endpoints. MiniMax adds `MINIMAX_API_REGION` (`global_en`/`cn_zh`) and `MINIMAX_API_PROTOCOL` (`openai`/`anthropic`). Vision OCR provider: `SKILL_SEEKER_VISION_PROVIDER` (`auto` picks the first image-capable provider with a key).
- **LOCAL mode** (fallback): Claude Code, Kimi Code, Codex, Copilot, OpenCode, custom agents β command built by `build_local_agent_command()`.
- Control: `--enhance-level 0` (off) / `1` (SKILL.md only) / `2` (default, balanced) / `3` (full)
- Agent selection: `--agent claude|codex|copilot|opencode|kimi|custom`
## Key Implementation Details
### Smart Categorization (`doc_scraper.py:smart_categorize()`)
Scores pages against category keywords: 3 points for URL match, 2 for title, 1 for content. Threshold of 2+ required. Falls back to "other".
### Content Extraction (`doc_scraper.py`)
`FALLBACK_MAIN_SELECTORS` constant + `_find_main_content()` helper handle CSS selector fallback. Links are extracted from the full page before early return (not just main content). `body` is deliberately excluded from fallbacks.
### Three-Stream GitHub Architecture (`unified_codebase_analyzer.py`)
Stream 1: Code Analysis (AST, patterns, tests, guides). Stream 2: Documentation (README, docs/, wiki). Stream 3: Community (issues, PRs, metadata). Depth control: `basic` (1-2 min) or `c3x` (20-60 min).
## Testing
### Test markers (pytest.ini)
```bash
pytest tests/ -v # Default: fast tests only
pytest tests/ -v -m slow # Include slow tests (>5s)
pytest tests/ -v -m integration # External services required
pytest tests/ -v -m e2e # Resource-intensive
pytest tests/ -v -m "not slow and not integration" # Fastest subset
```
### Known legitimate skips (~11)
- 2: chromadb incompatible with Python 3.14 (pydantic v1)
- 2: weaviate-client not installed
- 2: Qdrant not running (requires docker)
- 2: langchain/llama_index not installed
- 3: GITHUB_TOKEN not set
### sys.modules gotcha
`test_swift_detection.py` deletes `skill_seekers.cli` modules from `sys.modules`. It must save and restore both `sys.modules` entries AND parent package attributes (`setattr`). See the test file for the pattern.
## Dependencies
Core deps include `langchain`, `llama-index`, `anthropic`, `httpx`, `PyMuPDF`, `pydantic`. Platform-specific deps are optional:
```bash
pip install -e ".[mcp]" # MCP server
pip install -e ".[gemini]" # Google Gemini
pip install -e ".[openai]" # OpenAI
pip install -e ".[docx]" # Word documents
pip install -e ".[epub]" # EPUB books
pip install -e ".[video]" # Video (lightweight)
pip install -e ".[video-full]"# Video (Whisper + visual)
pip install -e ".[jupyter]" # Jupyter notebooks
pip install -e ".[pptx]" # PowerPoint
pip install -e ".[rss]" # RSS/Atom feeds
pip install -e ".[confluence]"# Confluence wiki
pip install -e ".[notion]" # Notion pages
pip install -e ".[chroma]" # ChromaDB
pip install -e ".[all]" # Everything (except video-full)
```
Dev dependencies use PEP 735 `[dependency-groups]` in pyproject.toml.
## Environment Variables
```bash
ANTHROPIC_API_KEY=sk-ant-... # Claude AI (or compatible endpoint)
ANTHROPIC_BASE_URL=https://... # Optional: Claude-compatible API endpoint
GOOGLE_API_KEY=AIza... # Google Gemini (optional)
OPENAI_API_KEY=sk-... # OpenAI (optional)
GITHUB_TOKEN=ghp_... # Higher GitHub rate limits
```
## Adding New Features
### New platform adaptor
1. Create `src/skill_seekers/cli/adaptors/{platform}.py` inheriting `SkillAdaptor` from `base.py`
2. Register in `adaptors/__init__.py` (add try/except import + add to `ADAPTORS` dict)
3. Add optional dep to `pyproject.toml`
4. Add tests in `tests/`
### New source type converter
1. Create `src/skill_seekers/cli/{type}_scraper.py` β for document-shaped sources inherit `DocumentSkillBuilder` (categorization/references/index/SKILL.md come free; implement `extract()` + hooks), otherwise inherit `SkillConverter` and implement `extract()` and `build_skill()`. Set `SOURCE_TYPE`.
2. Register in `CONVERTER_REGISTRY` in `skill_converter.py` β this also makes the type work in unified configs automatically (UnifiedScraper engine)
3. Add source type config building in `create_command.py:_build_config()`
4. Add auto-detection in `source_detector.py`
5. Add optional dep if needed
6. Add tests
### New CLI argument
- Subcommand flag: define ONLY in the central parser class (`parsers/{cmd}_parser.py`) β module `main()` builds from it; the drift-guard test fails otherwise
- Universal: `UNIVERSAL_ARGUMENTS` in `arguments/create.py`
- Source-specific: appropriate dict (`WEB_ARGUMENTS`, `GITHUB_ARGUMENTS`, etc.)
- Shared across scrapers: `add_all_standard_arguments()` in `arguments/common.py`