Skip to content

CLI

Semble ships as a standalone CLI. This is the best fit for sub-agents (which typically cannot call MCP tools directly), scripts, and anywhere you want search results without an MCP session. Indexes are built and cached on first run, and invalidated automatically when files change.

Install Semble first:

Terminal window
uv tool install semble # with uv (recommended)
pip install semble # with pip

Commands

Terminal window
# Search a local repo (index is built and cached automatically)
semble search "authentication flow" ./my-project
# Search for a symbol or identifier
semble search "save_pretrained" ./my-project
# Search a remote repo (cloned on demand)
semble search "save model to disk" https://github.com/MinishLab/model2vec
# Search several repos at once (results are prefixed with the repo name)
semble search "invoice endpoint" ./service-a ./service-b
# Limit results
semble search "save model to disk" ./my-project --top-k 10
# Show only the first N lines of each result's snippet (0 = path/line range only)
semble search "authentication flow" ./my-project --max-snippet-lines 10
# Search docs and prose (markdown, rst, etc.) instead of code
semble search "deployment guide" ./my-project --content docs
# Search config files (yaml, toml, terraform, etc.)
semble search "database host port" ./my-project --content config
# Search everything (code, docs, and config)
semble search "authentication" ./my-project --content all
# Find code similar to a known location
semble find-related src/auth.py 42 ./my-project
# Print the installed version
semble --version

--content accepts code (default), docs, config, or all, and can take several values (e.g. --content code docs). --format accepts json (default) or text. path defaults to the current directory when omitted; git URLs are accepted. If semble is not on $PATH, use uvx --from "semble[mcp]" semble in its place.

Searching multiple repos

Passing several paths or URLs searches them as one corpus, so a query from repo A can find an endpoint defined in repo B. Each index is cached per repo and merged at query time. Result paths are prefixed with the repo name (service-b/api/invoices.py) and the output includes a repos map from prefix to absolute path or URL. Pass the prefixed path to find-related to search across all repos from a known location.

Controlling which files are indexed

Semble reads .gitignore and .sembleignore files to determine which files to index. Both use standard gitignore syntax and their patterns are merged. .sembleignore lets you add Semble-specific rules without touching .gitignore. Rules are applied recursively, so a .sembleignore in a subdirectory applies to that subtree.

Excluding files:

.sembleignore
generated/ # exclude generated directory
*.pb.go # exclude Go protobuf files

Including non-default extensions: prefix the pattern with ! to force-include files Semble wouldn’t index by default:

.sembleignore
!*.proto # include Protobuf files
!*.cob # include COBOL files

Semble also always skips well-known non-source directories (node_modules/, .venv/, dist/, build/, __pycache__/, and similar) regardless of ignore files.

Files larger than 1 MB are skipped during indexing to keep index builds lean, and are reported as a warning at index time. To raise (or lower) this limit, set SEMBLE_MAX_FILE_BYTES to a size in bytes.

Storage

Indexes and token savings statistics are stored in the OS cache folder by default:

  • macOS: ~/Library/Caches/semble/
  • Linux: ~/.cache/semble/
  • Windows: %LOCALAPPDATA%\semble\Cache\

To override the location, set SEMBLE_CACHE_LOCATION to a full path:

Terminal window
export SEMBLE_CACHE_LOCATION=~/my-folder/semble

On first use, Semble also downloads the embedding model from Hugging Face and caches it in the standard Hugging Face cache (~/.cache/huggingface/ by default, or $HF_HOME if set). This only happens once and requires network access.

Use semble clear to remove cached data:

Terminal window
semble clear index # saved indexes
semble clear savings # usage stats
semble clear orphans # indexes for repos no longer present on disk
semble clear all # everything

Token savings

semble savings shows how many tokens Semble has saved across all your searches:

Terminal window
semble savings
Semble Token Savings
════════════════════════════════════════════════════════════════════════
Total saved: ~714.2M tokens (94%)
Total calls: 14.3k
Efficiency: ███████████████████████░ 94%
By Period
────────────────────────────────────────────────────────────────────────
Period Calls Saved Ratio
────────────────────────────────────────────────────────────────────────
Today 198 ~1.4M tokens ███████████████████████░ 95%
Last 7 days 13.1k ~707.2M tokens ███████████████████████░ 94%
All time 14.3k ~714.2M tokens ███████████████████████░ 94%
By Call Type
────────────────────────────────────────────────────────────────────────
# Call type Calls Share
────────────────────────────────────────────────────────────────────────
1. search 14.1k ████████████████ 99%
2. find_related 205 █░░░░░░░░░░░░░░░ 1%
════════════════════════════════════════════════════════════════════════

For each call, Semble records the total character count of the unique files containing returned chunks and the character count of the snippets returned. Estimated tokens saved is (file chars − snippet chars) / 4 (4 chars per token). This is a conservative estimate: the baseline is reading matched files in full, which is how coding agents often explore unfamiliar code.

Library usage

Semble can also be used as a Python library for programmatic access, useful when building custom tooling or integrating search directly into your own code.

from semble import ContentType, SembleIndex
# Index a local directory (code only, the default)
index = SembleIndex.from_path("./my-project")
# Index docs and prose (markdown, rst, etc.)
index = SembleIndex.from_path("./my-project", content=ContentType.DOCS)
# Index everything (code, docs, and config)
index = SembleIndex.from_path(
"./my-project",
content=[ContentType.CODE, ContentType.DOCS, ContentType.CONFIG],
)
# Index a remote git repository
index = SembleIndex.from_git("https://github.com/MinishLab/model2vec")
# Merge indexes from several repos into one (chunk paths are prefixed with the repo name)
index = SembleIndex.merge([
("./service-a", SembleIndex.from_path("./service-a")),
("./service-b", SembleIndex.from_path("./service-b")),
])
# Search the index with a natural-language or code query
results = index.search("save model to disk", top_k=3)
# Find code similar to a specific result
related = index.find_related(results[0], top_k=3)
# Each result exposes the matched chunk
result = results[0]
result.chunk.file_path # "model2vec/model.py"
result.chunk.start_line # 127
result.chunk.end_line # 150
result.chunk.content # "def save_pretrained(self, path: PathLike, ..."