Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 148 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Add Semble to Claude Code (requires [uv](https://docs.astral.sh/uv/getting-start
claude mcp add semble -s user -- uvx --from "semble[mcp]" semble
```

Using Codex, OpenCode, or Cursor? See [MCP Server](#mcp-server) for setup instructions.
Using another agent harness? See [MCP Server](#mcp-server) below for per-agent setup.

### Bash / AGENTS.md

Expand Down Expand Up @@ -83,7 +83,7 @@ If `semble` is not on `$PATH`, use `uvx --from "semble[mcp]" semble` in its plac

</details>

Once installed, run `semble savings` to see how many tokens Semble has saved you. Note that for sub-agent support in Claude Code or Codex, you need the full [Bash / AGENTS.md](#bash-agentsmd) setup below.
Note that sub-agents cannot call MCP tools directly, see [Bash / AGENTS.md](#bash-agentsmd) and [sub-agent setup](#sub-agent-setup) below for details.

<details>
<summary>Updating Semble</summary>
Expand All @@ -102,7 +102,7 @@ uv cache clean semble # for MCP users (restart your MCP client after)
- **Accurate**: NDCG@10 of 0.854 on our [benchmarks](#benchmarks), on par with code-specialized transformer models, at a fraction of the size and cost.
- **Token-efficient**: returns only the relevant chunks, using [~98% fewer tokens than grep+read](#benchmarks).
- **Zero setup**: runs on CPU with no API keys, GPU, or external services required.
- **MCP server**: works with Claude Code, Cursor, Codex, OpenCode, and any other MCP-compatible agent.
- **MCP server**: works with Claude Code, Cursor, Codex, OpenCode, VS Code, and any other MCP-compatible agent.
- **Local and remote**: pass a local path or a git URL.

## MCP Server
Expand All @@ -113,21 +113,51 @@ Semble can run as an MCP server so agents can search any codebase directly. Repo

> Requires [uv](https://docs.astral.sh/uv/getting-started/installation/) to be installed.

#### Claude Code
<details>
<summary>Claude Code</summary>

```bash
claude mcp add semble -s user -- uvx --from "semble[mcp]" semble
```

#### Codex
</details>

<details>
<summary>Cursor</summary>

Add to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in your project):

```json
{
"mcpServers": {
"semble": {
"command": "uvx",
"args": ["--from", "semble[mcp]", "semble"]
}
}
}
```

</details>

<details>
<summary>Codex</summary>

Add to `~/.codex/config.toml`:

```toml
[mcp_servers.semble]
command = "uvx"
args = ["--from", "semble[mcp]", "semble"]
```

#### OpenCode
</details>

<details>
<summary>OpenCode</summary>

Add to `~/.opencode/config.json`:

```json
{
"mcp": {
Expand All @@ -139,8 +169,31 @@ Add to `~/.opencode/config.json`:
}
```

#### Cursor
Add to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in your project):
</details>

<details>
<summary>VS Code</summary>

Add to `.vscode/mcp.json` in your project (or your user profile's `mcp.json`):

```json
{
"servers": {
"semble": {
"command": "uvx",
"args": ["--from", "semble[mcp]", "semble"]
}
}
}
```

</details>

<details>
<summary>GitHub Copilot CLI</summary>

Add to `~/.copilot/mcp-config.json`:

```json
{
"mcpServers": {
Expand All @@ -152,6 +205,81 @@ Add to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in your project):
}
```

</details>

<details>
<summary>Windsurf</summary>

Add to `~/.codeium/windsurf/mcp_config.json`:

```json
{
"mcpServers": {
"semble": {
"command": "uvx",
"args": ["--from", "semble[mcp]", "semble"]
}
}
}
```

</details>

<details>
<summary>Gemini CLI</summary>

Add to `~/.gemini/settings.json`:

```json
{
"mcpServers": {
"semble": {
"command": "uvx",
"args": ["--from", "semble[mcp]", "semble"]
}
}
}
```

</details>

<details>
<summary>Kiro</summary>

Add to `~/.kiro/settings/mcp.json` (or `.kiro/settings/mcp.json` in your project):

```json
{
"mcpServers": {
"semble": {
"command": "uvx",
"args": ["--from", "semble[mcp]", "semble"]
}
}
}
```

</details>

<details>
<summary>Zed</summary>

Add to `~/.config/zed/settings.json` (or `.zed/settings.json` in your project):

```json
{
"context_servers": {
"semble": {
"command": "uvx",
"args": ["--from", "semble[mcp]", "semble"]
}
}
}
```

</details>


### Tools

| Tool | Description |
Expand All @@ -164,9 +292,9 @@ Add to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in your project):

## Bash / AGENTS.md

An alternative to MCP is to invoke Semble via Bash. For Claude Code and Codex CLI, this is the only option for sub-agents, which cannot call MCP tools directly, though it can also be used alongside MCP for the top-level agent.
An alternative to MCP is to invoke Semble via Bash. Sub-agents cannot call MCP tools directly, so this is the only option for sub-agent support; it can also be used alongside MCP for the top-level agent.

To add Bash support, append the following to your `AGENTS.md` or `CLAUDE.md`:
To add Bash support, append the following to your `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, or equivalent:

```markdown
## Code Search
Expand Down Expand Up @@ -197,15 +325,20 @@ If `semble` is not on `$PATH`, use `uvx --from "semble[mcp]" semble` in its plac
4. Use grep only when you need exhaustive literal matches or quick confirmation of an exact string.
```

**Claude Code sub-agent**: Claude Code also supports a dedicated sub-agent. Run this once in your project root:
### Sub-agent setup

Claude Code, Gemini CLI, Cursor, OpenCode, GitHub Copilot CLI, and Kiro all support a dedicated semble search sub-agent. Run `semble init` once in your project root:

```bash
semble init
# or, if semble is not on $PATH:
uvx --from "semble[mcp]" semble init
semble init # Claude Code → .claude/agents/semble-search.md
semble init --agent gemini # Gemini CLI → .gemini/agents/semble-search.md
semble init --agent cursor # Cursor → .cursor/agents/semble-search.md
semble init --agent opencode # OpenCode → .opencode/agents/semble-search.md
semble init --agent copilot # Copilot CLI → .github/agents/semble-search.md
semble init --agent kiro # Kiro → .kiro/agents/semble-search.md
```

This writes [`.claude/agents/semble-search.md`](src/semble/agents/semble-search.md).
If semble is not on `$PATH`, prefix the command with `uvx --from "semble[mcp]"`.

## CLI

Expand Down
36 changes: 30 additions & 6 deletions src/semble/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import argparse
import asyncio
import sys
from enum import Enum
from importlib.resources import files
from importlib.util import find_spec
from pathlib import Path
Expand All @@ -11,10 +12,26 @@
from semble.stats import format_savings_report
from semble.utils import _format_results, _is_git_url, _resolve_chunk

_CLAUDE_FILE_PATH = Path(".claude") / "agents" / "semble-search.md"

class Agent(str, Enum):
CLAUDE = "claude"
COPILOT = "copilot"
CURSOR = "cursor"
GEMINI = "gemini"
KIRO = "kiro"
OPENCODE = "opencode"


_DEFAULT_AGENT = Agent.CLAUDE
_CLI_DISPATCH_ARGS = frozenset({"search", "find-related", "init", "savings", "-h", "--help"})


def _agent_path(agent: Agent) -> Path:
"""Return the project-relative path where the semble sub-agent file should be written."""
base_dir = ".github" if agent is Agent.COPILOT else f".{agent.value}"
return Path(base_dir) / "agents" / "semble-search.md"


def main() -> None:
"""Entry point for the semble command-line tool."""
if len(sys.argv) > 1 and sys.argv[1] in _CLI_DISPATCH_ARGS:
Expand Down Expand Up @@ -49,9 +66,9 @@ def _mcp_main() -> None:
asyncio.run(serve(args.path, ref=args.ref, include_text_files=args.include_text_files))


def _run_init(*, force: bool = False) -> None:
"""Write the Claude Code sub-agent file into the current project."""
dest = _CLAUDE_FILE_PATH
def _run_init(*, agent: Agent = _DEFAULT_AGENT, force: bool = False) -> None:
"""Write the semble sub-agent file for the given coding agent into the current project."""
dest = _agent_path(agent)
if dest.exists() and not force:
print(f"{dest} already exists. Run with --force to overwrite.", file=sys.stderr)
sys.exit(1)
Expand Down Expand Up @@ -89,7 +106,14 @@ def _cli_main() -> None:
help="Also index non-code text files (.md, .yaml, .json, etc.).",
)

init_p = sub.add_parser("init", help="Write .claude/agents/semble-search.md for Claude Code sub-agent support.")
init_p = sub.add_parser("init", help="Write a semble sub-agent file for your coding agent.")
init_p.add_argument(
"--agent",
"-a",
default=_DEFAULT_AGENT.value,
choices=[a.value for a in Agent],
help=f"Coding agent to set up (default: {_DEFAULT_AGENT.value}).",
)
init_p.add_argument("--force", action="store_true", help="Overwrite if the file already exists.")

savings_p = sub.add_parser("savings", help="Show token savings and usage stats.")
Expand All @@ -98,7 +122,7 @@ def _cli_main() -> None:
args = parser.parse_args()

if args.command == "init":
_run_init(force=args.force)
_run_init(agent=Agent(args.agent), force=args.force)
return

if args.command == "savings":
Expand Down
2 changes: 1 addition & 1 deletion src/semble/version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version_triple__ = (0, 1, 9)
__version_triple__ = (0, 1, 10)
__version__ = ".".join(map(str, __version_triple__))
4 changes: 3 additions & 1 deletion tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@

import pytest

from semble.cli import _CLAUDE_FILE_PATH, _cli_main, _run_init, main
from semble.cli import Agent, _agent_path, _cli_main, _run_init, main
from semble.types import SearchMode, SearchResult
from tests.conftest import make_chunk

_CLAUDE_FILE_PATH = _agent_path(Agent.CLAUDE)

_CLAUDE_AGENT_FILE = files("semble").joinpath("agents/semble-search.md").read_text(encoding="utf-8")


Expand Down
8 changes: 4 additions & 4 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading