Search SDK
RBS includes a powerful search engine built into every branch server. Search file contents, find files by name, and receive real-time file change notifications — all through a consistent API accessible from your editor or custom tooling.
Overview
| Feature | Description | Protocol |
|---|
| Content search | Search text or regex patterns across file contents. | REST API |
| Fuzzy file search | Quick file finder by name (like Cmd+P in your editor). | REST API |
| Streaming search | Real-time search results via Server-Sent Events. | SSE |
| File watcher | Real-time file change notifications. | WebSocket |
Content search
Search for text or regex patterns across all files in your workspace. Results include line numbers, column positions, and configurable context lines.
Basic search
# Simple text search
rbs search "TODO"
# Search with file type filter
rbs search "TODO" --include "*.py"
# Regex search
rbs search "func\s+\w+" --regex --include "*.go"
API: POST /api/search
Full search with all options via JSON body:
{
"query": "TODO|FIXME",
"path": "src/",
"is_regex": true,
"case_sensitive": false,
"whole_word": false,
"include_glob": "*.{ts,tsx}",
"exclude_glob": "*_test.ts",
"max_results": 100,
"context_lines": 2,
"max_file_size": 1048576
}
Parameters
| Field | Type | Default | Description |
|---|
query | string | required | Search pattern (text or regex). |
path | string | . | Directory to search (relative to workspace root). |
is_regex | boolean | false | Treat query as a regular expression. |
case_sensitive | boolean | false | Enable case-sensitive matching. |
whole_word | boolean | false | Match whole words only. |
include_glob | string | — | Only search files matching this glob pattern. |
exclude_glob | string | — | Skip files matching this glob pattern. |
max_results | number | 1000 | Maximum total matches to return. |
context_lines | number | 0 | Number of lines to include before and after each match. |
max_file_size | number | 1048576 | Skip files larger than this size (in bytes). |
Response
{
"results": [
{
"path": "src/utils/helper.ts",
"matches": [
{
"line": 42,
"column": 4,
"end_column": 8,
"content": " // TODO: implement caching",
"match_text": "TODO",
"pre_context": ["function getData() {", " const data = fetch('/api');"],
"post_context": [" return data;", "}"]
}
],
"truncated": false
}
],
"total_matches": 15,
"total_files": 8,
"files_searched": 234,
"duration": "45ms",
"truncated": false
}
API: GET /api/search (quick search)
Search via query parameters for simple lookups:
GET /api/search?q=TODO&include=*.ts&context=2&max=50
| Parameter | Aliases | Description |
|---|
q | query | Search pattern. |
path | — | Directory to search. |
regex | is_regex | Enable regex mode. |
case | case_sensitive | Case-sensitive search. |
word | whole_word | Whole word matching. |
include | include_glob | Include glob pattern. |
exclude | exclude_glob | Exclude glob pattern. |
max | max_results | Max results. |
context | context_lines | Context lines. |
Streaming search
For large workspaces, use the streaming endpoint to receive results in real-time via Server-Sent Events (SSE):
GET /api/search/stream?query=error&include=*.log
Results arrive as they’re found:
data: {"path":"app.log","matches":[{"line":1,"content":"Error: connection failed"}]}
data: {"path":"error.log","matches":[...]}
data: {"type":"done","total_matches":42,"total_files":5,"files_searched":100,"duration":"120ms","truncated":false}
Fuzzy file search
Find files quickly by name using fuzzy matching — the same experience as Cmd+P / Ctrl+P in your editor.
API: GET /api/files/fuzzy
GET /api/files/fuzzy?q=srvts&types=ts,tsx&max=20
| Parameter | Description | Default |
|---|
q or query | Fuzzy search query. | — |
types | Comma-separated file extensions to filter. | All types |
max | Maximum results. | 50 |
Response
{
"results": [
{
"path": "src/server.ts",
"name": "server.ts",
"directory": "src",
"score": 4.5,
"highlights": [0, 1, 2, 6, 7],
"is_dir": false,
"extension": ".ts",
"mod_time": 1706040000
}
],
"query": "srvts",
"total": 1,
"duration": "3ms",
"cached": true
}
An empty query returns recently modified files sorted by modification time — useful for “recent files” functionality.
How fuzzy matching works
The fuzzy matcher scores results based on:
- Character matching — all query characters must appear in order in the filename.
- Consecutive bonus — higher score for consecutive character matches.
- Word boundary bonus — higher score for matches at word boundaries (
/, _, -, ., camelCase).
- Prefix bonus — higher score for matches at the start of the filename.
- Exact match bonus — highest score for exact matches.
- Length penalty — shorter filenames score higher.
| Query | Matches | Why |
|---|
main.go | main.go | Exact match (highest score) |
main | main.go | Prefix match |
mg | main.go | Character matching |
srvts | server.ts | Word boundary + character matching |
btn | Button.tsx | Word boundary (camelCase) |
Refresh the file index
The file index refreshes automatically every 30 seconds. To force a refresh:
POST /api/files/index/refresh
{
"message": "file index refreshed",
"files_count": 1234
}
File watcher
Receive real-time notifications when files change in the workspace via WebSocket.
Connect
On connection, you’ll receive a confirmation message:
{
"type": "connected",
"workspace": "/workspace/my-project",
"message": "File watcher connected"
}
Event types
| Type | Description |
|---|
create | A file or directory was created. |
write | A file’s content was modified. |
remove | A file or directory was deleted. |
rename | A file or directory was renamed. |
chmod | File permissions were changed. |
{
"type": "write",
"path": "src/app.ts",
"name": "app.ts",
"is_dir": false,
"timestamp": 1706040001
}
For rename events, an additional old_path field is included:
{
"type": "rename",
"path": "src/new-name.ts",
"name": "new-name.ts",
"old_path": "src/old-name.ts",
"is_dir": false,
"timestamp": 1706040003
}
Debouncing
File events are debounced (100ms) to prevent rapid-fire notifications when editors auto-save, build tools generate multiple files, or external tools batch-modify files.
REST endpoints
| Method | Endpoint | Description |
|---|
GET | /api/watcher | Watcher info and configuration. |
GET | /api/watcher/status | Connection status. |
Default ignored patterns
All search and watcher features automatically skip:
.git, .hg, .svn directories
node_modules, vendor, __pycache__
.venv, venv, .env
dist, build, target
.idea, .vscode, .rbs
- Binary files (images, executables, archives)
- Files matching
.gitignore patterns
Glob pattern examples
| Pattern | Matches |
|---|
*.py | All Python files |
*.{ts,tsx} | TypeScript and TSX files |
test_*.py | Python test files starting with test_ |
src/**/*.go | All Go files under src/ |
Editor SDK integration
If you’re building a custom editor integration, use the Search SDK client:
import { RBSSearchClient } from "@rbs/editor-sdk";
const client = new RBSSearchClient("https://your-project.rbs.dev");
// Content search
const results = await client.search({
query: "TODO",
includeGlob: "*.ts",
contextLines: 2,
});
console.log(`Found ${results.total_matches} matches`);
// Streaming search
const cancel = client.searchStream(
"error",
(result) => console.log(`Found in ${result.path}`),
(summary) => console.log(`Done: ${summary.total_matches} matches`)
);
// Fuzzy file search
const files = await client.fuzzySearch("srvts", { max: 10 });
console.log(files.results.map((f) => f.path));
// File watcher
client.connectWatcher();
client.onFileChange((event) => {
console.log(`${event.type}: ${event.path}`);
});
# Content search
curl -X POST https://your-project.rbs.dev/api/search \
-H "Authorization: Bearer $RBS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query": "TODO", "include_glob": "*.py"}'
# Quick search
curl "https://your-project.rbs.dev/api/search?q=error&include=*.log&max=50" \
-H "Authorization: Bearer $RBS_TOKEN"
# Fuzzy file search
curl "https://your-project.rbs.dev/api/files/fuzzy?q=main&max=10" \
-H "Authorization: Bearer $RBS_TOKEN"
# Streaming search
curl -N "https://your-project.rbs.dev/api/search/stream?query=TODO" \
-H "Authorization: Bearer $RBS_TOKEN"
# Watcher status
curl "https://your-project.rbs.dev/api/watcher/status" \
-H "Authorization: Bearer $RBS_TOKEN"
- Use glob filters — always specify
include_glob when you know the file type.
- Limit results — set a reasonable
max_results for UI responsiveness.
- Use streaming for large searches — the SSE endpoint returns results as they’re found.
- Debounce user input — wait 100–200ms before sending search requests when building a search UI.
- Leverage the cache — fuzzy file search results are cached and respond in milliseconds.
- Connect the watcher once — reuse a single WebSocket connection for file change events.