This file provides guidance to AI coding agents (Claude Code, OpenCode, and others) when working with code in this repository. It is the single source of truth — AGENTS.md is a symlink to this file.
CocoSearch is a local-first hybrid semantic code search tool powered by CocoIndex and Tree-sitter. It indexes codebases into PostgreSQL with pgvector embeddings and provides search through CLI, MCP server, or interactive REPL. Local by default with Ollama; optional remote embedding providers (OpenAI, OpenRouter) available for teams that prefer managed infrastructure. Requires Python >=3.11.
When CocoSearch MCP tools are available, ALWAYS use them instead of Grep, Glob, or Task/Explore agents for code search and exploration. These rules are mandatory, not advisory. Violations degrade search quality and create unnecessary permission prompts.
| Task | Use this | NOT this |
|---|---|---|
| Code search / "how does X work?" | search_code |
Grep, Glob, Task (Explore) |
| Symbol lookup / "find function Y" | search_code with symbol_name/symbol_type |
Grep for def/class patterns |
| Dependency tracing / "what imports X?" | get_file_dependencies / get_file_impact |
Grep for import statements |
| Batch dependency analysis (multiple files) | get_batch_dependencies / get_batch_impact |
Per-file get_file_dependencies calls |
| Search debugging / "why no results?" | analyze_query |
Manual pipeline investigation |
Fall back to Grep/Glob ONLY for:
- Exact literal string matches (e.g., a specific error message or config value)
- File path pattern matching (e.g., "find all
*.test.tsfiles") - Editing operations that need line numbers from a known file
# Prerequisites: Docker, uv (Python package manager)
# One-command setup (starts infra, pulls model, installs deps, indexes codebase):
./dev-setup.sh
# Or manually:
docker compose --profile ollama up -d # PostgreSQL 17 + Ollama
uv sync # Install dependencies
uv run cocosearch index . # Index the codebaseInfrastructure: PostgreSQL 17 (pgvector) on port 5432, Ollama on port 11434. Defaults require no .env file.
# Run all unit tests (default, mocked, no infra needed). Takes a long time.
uv run pytest
# Run a single test file
uv run pytest tests/unit/search/test_cache.py -v
# Run a single test by name
uv run pytest -k "test_rrf_double_match_ranks_higher" -v
# Run handler tests
uv run pytest tests/unit/handlers/ -v
# Lint and format
uv run ruff check src/ tests/
uv run ruff check --fix src/ tests/ # Auto-fix lint issues
uv run ruff format src/ tests/ # Format code
# CLI usage
uv run cocosearch index .
uv run cocosearch search "query"
uv run cocosearch search -i # Interactive REPL
uv run cocosearch search -i --indexes "repo_a,repo_b" # Cross-index interactive REPL
uv run cocosearch search --indexes "repo_a,repo_b" "query" # Cross-index search
uv run cocosearch analyze "query" # Pipeline analysis with diagnostics
uv run cocosearch analyze "query" --json # JSON pipeline analysis
uv run cocosearch analyze --indexes "repo_a,repo_b" "query" # Cross-index analysis
uv run cocosearch stats
uv run cocosearch list
uv run cocosearch clear <index>
uv run cocosearch clear idx1 idx2 # Delete multiple indexes
uv run cocosearch clear --all # Delete all indexes
uv run cocosearch languages # List supported languages
uv run cocosearch grammars # List supported grammars
uv run cocosearch init # Initialize cocosearch.yaml + optional CLAUDE.md/AGENTS.md
uv run cocosearch init --no-claude-md # Initialize without CLAUDE.md prompt
uv run cocosearch init --no-agents-md # Initialize without AGENTS.md prompt
uv run cocosearch init --no-opencode-mcp # Initialize without OpenCode MCP registration prompt
uv run cocosearch init --no-opencode-skills # Initialize without OpenCode skills installation prompt
uv run cocosearch init --no-claude-mcp # Initialize without Claude Code plugin prompt
uv run cocosearch init --no-claude-settings # Initialize without Claude Code permissions prompt
uv run cocosearch init --no-claude-hook # Initialize without Claude Code nudge-hook prompt
uv run cocosearch config show
uv run cocosearch config path
uv run cocosearch config check
uv run cocosearch dashboard # Terminal dashboard
# Dependency graph (incremental by default, use --fresh for full re-extraction)
uv run cocosearch index . --deps # Index + extract dependencies
uv run cocosearch deps extract . # Extract dependencies (incremental)
uv run cocosearch deps extract . --fresh # Force full re-extraction
uv run cocosearch deps show <file> # Show dependencies for a file
uv run cocosearch deps tree <file> # Forward dependency tree (transitive)
uv run cocosearch deps impact <file> # Reverse impact tree (what depends on this)
uv run cocosearch deps stats # Show dependency graph statistics
# MCP server
uv run cocosearch mcp --project-from-cwdEntry points: cocosearch.cli:main (CLI) and cocosearch.mcp.server (MCP via FastMCP).
Module structure:
cli.py— Argparse CLI orchestrating all subcommands. WhenCOCOSEARCH_SERVER_URLis set, dispatches toclient.pyinstead of local execution.client.py— HTTP client for remote server mode.CocoSearchClientforwards CLI commands to a running CocoSearch server via HTTP API (/api/search,/api/index,/api/stats,/api/list,/api/analyze,/api/languages,/api/grammars,/api/delete-index). Path translation viaCOCOSEARCH_PATH_PREFIXrewrites host↔container paths.exceptions.py— Structured exception hierarchy:CocoSearchError(base),IndexNotFoundError,IndexValidationError,SearchError,InfrastructureError. Inherits fromValueErrorwhere needed for backward compatibility.validation.py— Input validation guards:validate_index_name()(SQL injection protection for dynamic table names),validate_query()(resource exhaustion protection, max 10,000 chars)ts_parsers.py— Single thread-local provider for tree-sitterParserobjects (get_parser(language)). tree-sitterParseris unsendable in the pyo3 bindings (panics if used off its creating thread), and indexing/deps extraction run in background worker threads (e.g. dashboard reindex spawns a fresh thread per click), so parsers are cached per-thread viathreading.local()— never shared across threads. All parser acquisition (symbol extraction, deps extractors, parse-health tracking inindexer/parse_tracking.py, search context expansion insearch/context_expander.py) must route through this module rather than constructing or cachingParserdirectly.mcp/server.py— MCP server exposing tools (search_code, analyze_query, index_codebase, open_dashboard, get_file_dependencies, get_file_impact, get_batch_dependencies, get_batch_impact, etc.) + web dashboard with HTTP API (/api/stats,/api/reindex,/api/search,/api/project,/api/projects,/api/index,/api/stop-indexing,/api/delete-index,/api/list,/api/analyze,/api/languages,/api/grammars,/api/credits,/api/open-in-editor,/api/file-content,/api/deps,/api/deps/impact,/api/deps/graph,/health,/api/heartbeatSSE,/api/logsSSE,/api/shutdownPOST)./api/creditsreports remaining credits for a remote provider (OpenRouter) and powers the dashboard header'sCREDITS:indicator; the controller status (REWRITE: ON/OFF) is injected into/api/statsand shown alongside it in the header status line. While an index is actively (re)building,/api/statsalso carries liveindexing_progress(files_done/files_total/chunks) — tracked in the module-level_indexing_progressmap (guarded by_indexing_lock, fed byrun_index'sprogress_callback, cleared when the worker finishes), attached in_apply_thread_liveness_status, and rendered on the dashboard Status card during indexing. Both background-index worker closures catchBaseException(not justException) so a pyo3 panic can't leave an index stuck in "indexing".search_codeaccepts arewrite_queryflag (default True) to opt out of the optional query-rewrite controller. Bridges the controller config to env vars at startup. Includes idle watchdog for stdio transport (auto-exits afterCOCOSEARCH_IDLE_TIMEOUTseconds of inactivity, default 30 min)logging.py— Structured domain logger (cs_log) with category-specific methods (search,index,mcp,cache,infra,system,deps). Each method creates aLogEntrywith category and structured fields, pushing toLogBufferfor unified output. Falls back to Python logging when no buffer is initialized.LogCategoryenum defines the 7 categories.mcp/log_stream.py— Real-time log capture for dashboard:LogEntry(withcategoryandfields),LogBufferring buffer with SSE pub/sub and handler fan-out,BufferHandler(logging.Handler),StderrCapture(tee wrapper for CocoIndex framework output),RichLogHandler(color-coded terminal output via Rich),FileLogHandler(rotating log file at~/.cocosearch/logs/),setup_log_capture()singleton lifecyclemcp/project_detection.py— Auto-detect project from MCP Roots or CWDindexer/— Indexing pipeline: file filtering (file_filter.py), Tree-sitter symbol extraction (16 languages via.scmqueries inindexer/queries/), multi-provider embedding (embedder.py— Ollama/OpenAI/OpenRouter via LiteLLM,embed_query()for search-side embedding), tsvector generation, parse health tracking, schema migration, preflight validation (preflight.py— conditional Ollama vs API key checks), progress reporting (progress.py). Uses CocoIndex'sRecursiveSplitterfor chunking andCustomLanguageConfigfor language specs.indexer/flow.py— Indexing pipeline: incremental file processing with SHA-256 content hashing, psycopg-based PostgreSQL storage, pgvector embeddings.run_index()orchestrates file discovery → diff → chunk → embed → upsert, and accepts an optionalprogress_callback(files_done, files_total, chunks)(invoked at start and at the progress-log cadence) used to surface live progress on the dashboard.search/— Hybrid search engine: RRF fusion of vector + keyword results, two-level LRU query cache (cache.py— exact + semantic similarity at cosine > 0.92), context expansion via Tree-sitter boundaries for 10 languages (context_expander.py, exportsCONTEXT_EXPANSION_LANGUAGES), symbol/language filtering (filters.py), auto-detection of code identifiers for hybrid mode (query_analyzer.py), optional LLM query-rewrite controller that expands natural-language queries to better search terms before retrieval (controller.py— default OFF, configured like the embedding provider, total fallback to the original query on any error/timeout/disabled; applied once before cache/embedding insearch()and once before fan-out inmulti_search()), optional dependency enrichment (include_depsattaches direct dependencies/dependents to search results), interactive REPL with cross-index support (repl.py—:indexes,:searchallcommands), result formatting (formatter.py), pipeline analysis with stage-by-stage diagnostics and cross-indexmulti_analyze()(analyze.py), cross-index orchestrator (multi.py)search/multi.py— Cross-index search orchestrator:multi_search()queries multiple indexes in parallel viaThreadPoolExecutor, pre-computes query embedding once, tags results with sourceindex_name, merges by score. Handles partial failures gracefully. Accepts optionalwarningslist to surface embedding model mismatch warnings to callers.search/db.py— PostgreSQL connection pool (singleton) and query executionconfig/— YAML config with 4-level precedence resolution (CLI > env > file > defaults),${VAR}substitution (env_substitution.py), Pydantic schema validation (schema.pywithextra="forbid",strict=True,EmbeddingSectionwithproviderfield, provider-aware model defaults, and optionalbaseUrlfor custom endpoints,ControllerSectionfor the optional query-rewrite controller —enabled(default False),provider/model/baseUrl/timeout, mirrors the embedding provider pattern,LoggingSectionwithfiletoggle,linkedIndexeslist for cross-index search auto-expansion), user-friendly error formatting with fuzzy field suggestions (errors.py), env var validation (env_validation.py).resolver.bridge_controller_config()bridges the controller config toCOCOSEARCH_CONTROLLER_*env vars (must be called at each search entry point, unlike embedding).generator.pypowerscocosearch init: writescocosearch.yaml, CLAUDE.md/AGENTS.md routing, OpenCode MCP/skills, Claude Code permissions (generate_claude_settings), and the optional PreToolUse nudge hook (generate_claude_hook) — a non-blocking, availability-gated hook that injects anadditionalContextreminder steering the agent towardsearch_codeinstead of raw Grep/Glob/grep/find/rg when CocoSearch's Postgres backend is reachable (host/port read fromCOCOSEARCH_DATABASE_URLat hook time, default127.0.0.1:5432; silent otherwise; tagged withCOCOSEARCH_NUDGE_MARKERfor idempotent reinstall). All generators merge into existing files, preserving unrelated keys.management/— Index lifecycle: discovery (discovery.py), stats (stats.py—collect_warnings()runs staleness, branch drift, and deps freshness checks for both the main index and alllinkedIndexes;check_linked_index_health()is the standalone reusable helper for linked index validation used by CLI and MCP after indexing; includescheck_deps_staleness()for dependency freshness checks), clearing (clear.py—check_linked_index_references()warns before deleting indexes listed inlinkedIndexes), git-based naming (git.py), metadata with collision detection, status tracking, embedding provider/model tracking, anddeps_extracted_attimestamp (metadata.py), project root detection (context.py)deps/— Dependency graph framework: pluggable extractors (extractors/), pluggable module resolvers (resolver.py), edge storage (db.py), extraction orchestrator (extractor.py), query API with transitive BFS traversal (query.py), data models (models.py), autodiscovery registry (registry.py). 11 extractors: Python imports, JavaScript/TypeScript (ES6 + CommonJS + re-exports), Go imports, ArgoCD (Application/ApplicationSet/AppProject — project refs, source repos/charts/paths, destinations, generator repos; multi-document YAML viasafe_load_all), Docker Compose (image/depends_on/extends), GitHub Actions (uses refs with parsed owner/repo/version, needs inter-job deps), GitLab CI (include local/project/remote/template, extends template inheritance, needs DAG deps, trigger child/multi-project pipelines, image/service refs), Terraform (module sources with version, required_providers, remote_state, tfvars associations), Helm (template includes, Chart.yaml subcharts, chart membership ownership withis_subchartindicator, subchart-to-parent links), Markdown (documentation references: frontmatter depends, links, inline code, code blocks). 5 module resolvers: Python (dotted modules,__init__.py, relative imports,src//lib/prefix stripping), JavaScript (extension probing, index files), Go (import path suffix matching), Terraform (local module sources), Markdown (relative path normalization, directory reference matching). Query layer supports direct lookups (get_dependencies/get_dependents), transitive BFS trees (get_dependency_tree/get_impactwith cycle detection and depth limits), batch-aware multi-root BFS (get_dependency_tree_batch/get_impact_batchwith shared visited set), and detailed stats (get_dep_stats_detailed). Three edge types: "import" (code imports), "call" (symbol calls), "reference" (grammar-level refs withmetadata.kindfor specifics — Helm useschart_memberfor template/values→Chart.yaml ownership andsubchart_offor subchart→parent chart links).handlers/— Language-specific chunking (HCL, Go Template, Dockerfile, Bash, Scala, Groovy) and grammar handlers (handlers/grammars/— ArgoCD, Helm Chart, Helm Template, Helm Values, GitHub Actions, GitLab CI, Docker Compose, Kubernetes, Terraform) with autodiscovery registrydashboard/— Terminal (Rich) and web (Chart.js) dashboards. In stdio MCP mode,server.pylaunches uvicorn in a daemon thread running the MCP server'ssse_app()— all routes are served from a single source of truth (no duplicated handlers). Web static assets are split into ES modules:dashboard/web/static/index.html(HTML only),css/styles.css, andjs/with modules (app.jsentry point,state.jsshared state,api.js,utils.js,charts.js,dashboard.js,index-mgmt.js,search.js,logs.js,theme.js). Supports light (sepia parchment) and dark (Coco Orange Phosphor) themes viatheme.js— OS preference (prefers-color-scheme) on first visit, user choice persisted inlocalStorage['cocosearch-theme'], with a FOUC-prevention inline script in<head>and Prism stylesheet swapping; charts and tab favicon re-read CSS variables on theme change. Static files served via/static/{path}route with path traversal protection..claude-plugin/— Claude Code plugin metadata:plugin.json(MCP server definition, version, keywords) andmarketplace.json(marketplace listing). Versions must matchpyproject.toml— the release workflow syncs them automatically.
Data flow: Files → Tree-sitter parse → symbol extraction → chunking → embeddings (Ollama/OpenAI/OpenRouter) → PostgreSQL (pgvector). Search queries → embedding → hybrid RRF (vector similarity + tsvector keyword) → context expansion → results. Cross-index search: query → single embedding → parallel per-index search → score-based merge → unified results. linkedIndexes config auto-expands single-index searches to cross-index when linked indexes exist.
Key patterns:
- Singleton DB connection pool via
search.db— reset between tests withreset_db_pool()autouse fixture intests/conftest.py - Handler autodiscovery: any
handlers/*.py(not prefixed with_) implementingLanguageHandlerprotocol is auto-registered. Grammar handlers inhandlers/grammars/*.pyare also autodiscovered. YAML-based grammar handlers inherit fromYamlGrammarBase(handlers/grammars/_base.py) for shared comment stripping, matching, and fallback metadata chain.include_patternsinIndexingConfigare auto-derived from handlerEXTENSIONSand grammarPATH_PATTERNS. - Indexing pipeline in
indexer/flow.pyuses psycopg directly with SHA-256 content hashing for incremental updates. CocoIndex is used only forRecursiveSplitter(chunking) andCustomLanguageConfig(language specs) — no CocoIndex runtime, flows, or App objects. - Table naming:
codeindex_{index_name}__{index_name}_chunks. Parse results go tococosearch_parse_results_{index_name}. File tracking hashes go tococosearch_index_tracking_{index_name}. - Parse status categories:
ok,partial,error,no_grammar. Text-only formats (md, yaml, json, etc.) are skipped from parse tracking entirely via_SKIP_PARSE_EXTENSIONSinindexer/parse_tracking.py. - Dependency extractor autodiscovery: any
deps/extractors/*.py(not prefixed with_) implementingDependencyExtractorprotocol is auto-registered. Lookup bylanguage_id(file extension or grammar name, e.g., "py", "js", "go", "md", "mdx", "docker-compose", "github-actions", "terraform", "helm-template", "helm-values", "helm-chart"). Dependency edges stored incocosearch_deps_{index_name}. Module resolvers indeps/resolver.pyare registered per language_id and resolve module names to file paths after extraction. Extraction is incremental by default: SHA-256 content hashes tracked incocosearch_deps_tracking_{index_name}detect changed/added/deleted files; only dirty files are re-extracted, then ALL edges are re-resolved for correctness. Successful extraction stampsdeps_extracted_atincocosearch_index_metadatafor staleness detection by MCP dependency tools. Use--freshto force full re-extraction.
All tests are unit tests (tests/unit/), fully mocked and requiring no infrastructure. uv run pytest runs them by default.
Markers are auto-applied by conftest.py — tests under tests/unit/ get @pytest.mark.unit automatically. No need to add them manually.
Async tests use pytest-asyncio with strict mode — async test functions must be decorated with @pytest.mark.asyncio.
Shared fixtures live in tests/fixtures/.
Symbol extraction tests live in tests/unit/indexer/symbols/ (one file per language). Handler tests are in tests/unit/handlers/.
Dashboard tests in tests/unit/dashboard/ include HTML structure tests (test_html_structure.py) and ASGI integration tests (test_dashboard_serving.py) that exercise the full Starlette stack via httpx.AsyncClient + ASGITransport. API smoke tests in tests/unit/mcp/test_api_smoke.py similarly test key endpoints through the ASGI app. When adding dashboard routes or static assets, add corresponding ASGI integration tests.
Three independent systems — a language can use any combination. See docs/adding-languages.md for the full guide.
Language Handler (custom chunking for languages not in CocoIndex's built-in list):
- Copy
src/cocosearch/handlers/_template.pyto<language>.py - Define
EXTENSIONS,SEPARATOR_SPEC(usingCustomLanguageConfig), andextract_metadata() - Include patterns are auto-derived from
EXTENSIONS— no manualconfig.pyedit needed - Separators must use standard regex only — no lookaheads/lookbehinds (CocoIndex uses Rust regex)
- Create
tests/unit/handlers/test_<language>.py
Symbol Extraction (enables --symbol-type/--symbol-name filtering):
- Create
src/cocosearch/indexer/queries/<language>.scmwith tree-sitter queries - Add the language to
LANGUAGE_MAPinsrc/cocosearch/indexer/symbols.py - Create
tests/unit/indexer/symbols/test_<language>.py
Grammar Handler (domain-specific chunking within a base language, e.g. GitHub Actions within YAML):
- Copy
src/cocosearch/handlers/grammars/_template.pyto<grammar>.py - For YAML-based grammars, inherit
YamlGrammarBaseand implement_has_content_markers()and_extract_grammar_metadata() - Create
tests/unit/handlers/grammars/test_<grammar>.py
Workflow skills are SKILL.md files that guide AI coding assistants through structured workflows using CocoSearch MCP tools.
- Create
skills/cocosearch-<name>/SKILL.mdwith YAML frontmatter (name,description) and the workflow steps - Run
./scripts/sync_skills.shto sync skills into the Python package - Add to the skills table in
skills/README.md - Add to all installation
forloops inskills/README.md(Claude Code project-local, global, OpenCode project-local, global) - Update skill count in
skills/README.md("all N skills") - Add to the Workflow Skills list in the Plugin Usage section of this file
- Update
tests/unit/config/test_generator.pyexpected skill count
Skills are autodiscovered by _get_bundled_skills() in src/cocosearch/config/generator.py — any cocosearch-* subdirectory under src/cocosearch/skills/ with a SKILL.md is included automatically. No manual registration in code is needed.
Project config via cocosearch.yaml (no leading dot) in project root. The indexName field sets the index name used by all commands. The linkedIndexes field (list of strings) declares related indexes for automatic cross-index search expansion — when set, search tools auto-include linked indexes without requiring explicit index_names parameter (missing linked indexes are skipped gracefully; explicit index_names overrides config). Environment variables prefixed with COCOSEARCH_ (e.g., COCOSEARCH_DATABASE_URL, COCOSEARCH_OLLAMA_URL). Config keys map to env vars via camelCase→UPPER_SNAKE conversion (e.g., indexName → COCOSEARCH_INDEX_NAME). COCOSEARCH_EDITOR is a runtime env var (not a config field) for the dashboard's "Open in Editor" feature — falls back to $EDITOR then $VISUAL. See .env.example for available options.
Logging: Log file output is disabled by default. Enable via logging.file: true in cocosearch.yaml or COCOSEARCH_LOG_FILE=true env var. Logs are written to ~/.cocosearch/logs/cocosearch.log with 10MB rotation and 3 backups. The web dashboard log panel supports category filtering (search, index, mcp, cache, infra, system, deps) and level filtering (DEBUG+, INFO+, WARN+, ERROR+).
Embedding providers: CocoSearch supports multiple embedding providers: ollama (default, local), openai, and openrouter. Provider selection is via COCOSEARCH_EMBEDDING_PROVIDER env var or the embedding.provider field in cocosearch.yaml. Remote providers require COCOSEARCH_EMBEDDING_API_KEY (unless baseUrl is set for local OpenAI-compatible servers). COCOSEARCH_EMBEDDING_BASE_URL (or embedding.baseUrl in config) overrides the provider's default endpoint — use it with local OpenAI-API-compatible servers (Infinity, text-embeddings-inference, vLLM). For the ollama provider, baseUrl overrides COCOSEARCH_OLLAMA_URL. Default models: ollama→nomic-embed-text, openai→text-embedding-3-small, openrouter→openai/text-embedding-3-small. Index metadata tracks which provider/model was used; switching requires --fresh reindex.
Query-rewrite controller (optional, default-off): An LLM can rewrite/expand a natural-language query into better search terms before retrieval (e.g. "how does login work" → "authentication session credential login user token"). Disabled by default — when off, search behavior is byte-for-byte identical and no generative model is called. Enable via the controller block in cocosearch.yaml (enabled: true, provider = ollama/openai/openrouter, optional model/baseUrl/timeout) or COCOSEARCH_CONTROLLER_* env vars (_ENABLED, _PROVIDER, _MODEL, _BASE_URL, _TIMEOUT, _API_KEY). Configured exactly like the embedding provider; defaults to local Ollama (qwen2.5:3b). When no COCOSEARCH_CONTROLLER_API_KEY is set and the controller uses the same provider as embedding, it reuses COCOSEARCH_EMBEDDING_API_KEY (so you don't duplicate the key when both run on, e.g., openrouter). The controller never breaks search — on any error/timeout/garbage output it falls back to the original query. Opt out per-call with the CLI --no-rewrite flag, the analyze --no-rewrite flag, or the MCP search_code(rewrite_query=False) parameter (recommended when the agent has already crafted precise terms). NOTE: CocoSearch retrieval is already deterministically adaptive (auto hybrid-vs-vector selection, dynamic prefetch, definition boost, two-level cache) without any LLM — the controller is an optional layer on top, mainly useful for vague human queries on the CLI/REPL.
Docker / client mode env vars:
COCOSEARCH_SERVER_URL— When set, CLI forwards commands to the remote server instead of running locally (e.g.,http://localhost:3000)COCOSEARCH_PATH_PREFIX— Host↔container path rewriting for client mode (e.g.,~/GIT:/projects)COCOSEARCH_PROJECTS_DIR— Directory to scan for available projects. Dashboard shows unindexed projects with an "Index Now" option. Defaults to.incocosearch dashboard; set to/projectsin docker-compose.yml. Override with--projects-dirflag.PROJECTS_DIR— Docker Compose variable: directory to mount into the app container as/projects(default:.)COCOSEARCH_MCP_PORT— Server port, used by both CLI and Docker Compose (default:3000)COCOSEARCH_IDLE_TIMEOUT— Idle timeout in seconds for stdio MCP servers; auto-exits after inactivity (default:1800/ 30 min,0to disable)
Docker deployment:
docker compose --profile app --profile ollama up --build # Full stack (local embeddings)
docker compose --profile app up --build # DB + app only (remote embeddings)
docker compose --profile ollama up -d # PostgreSQL + Ollama (local dev)Docker MCP (SSE transport): The container runs an SSE-based MCP server. Connect AI assistants directly via URL instead of spawning a local process:
claude mcp add --scope user cocosearch --url http://localhost:3000/sseAlways update documentation when making code changes. This includes:
- CLAUDE.md / AGENTS.md — Update module descriptions, counts, patterns, and commands when adding/removing/modifying modules, handlers, CLI commands, MCP tools, or architectural patterns.
AGENTS.mdis a symlink toCLAUDE.md, so only one file needs editing. - docs/ — Update relevant docs (
architecture.md,how-it-works.md,retrieval.md,adding-languages.md) when changing the systems they describe - README.md — Update feature lists, usage examples, or screenshots when user-facing behavior changes
.claude-plugin/— Plugin version files (plugin.json,marketplace.json) andsrc/cocosearch/__init__.pymust stay in sync withpyproject.toml. The release workflow handles this automatically. If editingmarketplace.jsondescriptions orplugin.jsonmetadata manually, ensure accuracy (skill count, server command).
Documentation updates should be part of the same change, not deferred to a follow-up.
When this plugin is active, you have access to MCP tools and workflow skills for code search.
search_code— Semantic + keyword hybrid search. Always useuse_hybrid_search=Trueandsmart_context=True. Optionalinclude_deps=Trueattaches dependency info to results. Optionalindex_namesparameter for cross-index search across multiple projects. Auto-expands to includelinkedIndexesfromcocosearch.yamlwhenindex_namesis not explicitly provided. Optionalrewrite_query=Falseopts out of the query-rewrite controller (when enabled) — use it for precise, already-crafted queries.analyze_query— Pipeline diagnostics: see why a query returns specific results (stage timings, mode selection, RRF fusion breakdown). Optionalindex_namesparameter for cross-index analysis with per-index breakdowns.index_codebase— Index a directory for searchlist_indexes— List all available indexesindex_stats— Statistics and health for an indexclear_index— Remove one or more indexes (supportsindex_namefor single,index_namesfor bulk deletion)open_dashboard— Reopen the CocoSearch web dashboard in the user's browser. The dashboard runs in the background for the lifetime of the MCP server; use this when the tab was closed and the user wants it back.get_file_dependencies— Forward dependency query: what does a file depend on?depth=1returns flat edge list,depth>1returns transitive tree. Includes staleness warnings when deps are outdated.get_file_impact— Reverse impact query: what would be affected if a file changes? Returns transitive impact tree. Includes staleness warnings when deps are outdated.get_batch_dependencies— Batch forward dependency query for multiple files. Shared visited set eliminates redundant traversal of overlapping subgraphs. More efficient than per-file calls for git diff analysis. Includes staleness warnings.get_batch_impact— Batch reverse impact query for multiple files. Shared visited set across all roots. More efficient than per-file calls for change blast radius analysis. Includes staleness warnings.
- Always check
cocosearch.yamlforindexNamefirst — use it for all operations use_hybrid_search=True— combines semantic + keyword via RRF fusionsmart_context=True— expands to full function/class boundaries via Tree-sittersymbol_namewith glob patterns for precision (e.g.,User*)symbol_typefor structural filtering: "function", "class", "method", "interface"rewrite_query=False— pass this when you have already crafted precise/structured queries (exact identifiers,symbol_name/symbol_typefilters, known terms) to search them verbatim. Leave it at the default (True) only when forwarding a user's vague natural-language phrasing. No effect unless the optional query-rewrite controller is enabled incocosearch.yaml.- ALWAYS use CocoSearch tools instead of Grep/Glob for code search — see "Tool Routing" section above
/cocosearch:cocosearch-quickstart— First-time setup and verification/cocosearch:cocosearch-onboarding— Guided codebase tour/cocosearch:cocosearch-explore— "How does X work?" (autonomous or interactive)/cocosearch:cocosearch-debugging— Root cause analysis/cocosearch:cocosearch-deps— Dependency graph exploration (impact, connections, hubs)/cocosearch:cocosearch-refactoring— Impact analysis and safe refactoring/cocosearch:cocosearch-new-feature— Pattern-matching feature development/cocosearch:cocosearch-add-language— Add language support (handlers, symbols, context expansion)/cocosearch:cocosearch-add-grammar— Add grammar handler (domain-specific formats within a base language)/cocosearch:cocosearch-add-extractor— Add dependency extractor (enablesdeps tree,deps impact, dependency-enriched search)/cocosearch:cocosearch-review-pr— Review GitHub PRs / GitLab MRs with blast radius and dependency analysis; optionally push findings back as inline comments (interactive, comment-only)/cocosearch:cocosearch-commit— Smart commit messages: analyzes diffs with semantic search and dependency impact
Docker running PostgreSQL 17 (pgvector) on port 5432 and Ollama on port 11434. Use /cocosearch:cocosearch-quickstart to verify.