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
38 changes: 21 additions & 17 deletions .agents/skills/omni-graph/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,12 @@ The stdio MCP server runs hermetically via `tools/omni-graph/scripts/omni-mcp.py
"tools": [
{
"name": "omni_definition",
"description": "Lookup precise AST definition, signatures, and file line ranges for a code symbol.",
"description": "Lookup precise AST definition, signatures, and file line ranges for a code symbol. Includes in-band implementation body.",
"parameters": {
"symbol": "string (required) — Exact identifier name (function, struct, class, interface)",
"workspace": "string (optional) — Workspace name (defaults to auto-detected Git root)"
"symbol": "string (required) — Identifier name, qualified symbol (e.g., 'Class.method'), or file-scoped path ('path/file.py:func')",
"workspace": "string (optional) — Workspace name (defaults to auto-detected Git root)",
"include_body": "boolean (optional, default true) — Include full code body in-band (dynamically adapts budget if >3 matches)",
"force_full_bodies": "boolean (optional, default false) — Force full code body inclusion even for multiple ambiguous matches"
}
},
{
Expand All @@ -143,7 +145,9 @@ The stdio MCP server runs hermetically via `tools/omni-graph/scripts/omni-mcp.py
"query": "string (required) — Natural language or technical concept",
"k": "integer (optional, default 10) — Number of top results",
"workspace": "string (optional) — Target workspace name",
"include_docs": "boolean (optional, default false) — Include markdown documentation nodes"
"include_docs": "boolean (optional, default false) — Include markdown documentation nodes",
"exclude_tests": "boolean (optional, default false) — Pre-KNN filter excluding test files, test directories, and benchmark files",
"path_prefix": "string (optional) — Filter vector search results strictly within subtrees matching prefix"
}
},
{
Expand Down Expand Up @@ -178,19 +182,19 @@ The command-line wrapper lives at `./scripts/omni` (symlinked to `tools/omni-gra
./scripts/omni worktrees [sync] # Scan & synchronize ephemeral Git worktrees

# AST Code Intelligence
./scripts/omni symbol <name> [ws] # Locate symbol definition, line bounds, and code snippet
./scripts/omni references <name> [ws] # Locate all callers, importing files, and test suites
./scripts/omni condense <name> [ws] [h] # Extract <1500-token PPR-condensed call graph slice (hops: 1 or 2)
./scripts/omni search <query> [ws] [k] # Dense vector semantic code search (top k)
./scripts/omni galaxies [ws] # ASCII table of modular architectural subsystems & coupling metrics
./scripts/omni query <prompt> [ws] [k] # Hybrid Graph-RAG architectural brief
./scripts/omni relate <src> <tgt> [t] # Inject dynamic/inferred runtime relationship edge (CALLS, ROUTES_TO)
./scripts/omni symbol <name|Class.method|path:symbol> [ws] # Locate symbol definition, line bounds, and code snippet
./scripts/omni references <name> [ws] # Locate all callers, importing files, and test suites
./scripts/omni condense <name> [ws] [h] # Extract <1500-token PPR-condensed call graph slice (hops: 1 or 2)
./scripts/omni search <query> [ws] [k] [--exclude-tests|-x] [--path-prefix|-p <p>] # Dense vector semantic code search
./scripts/omni galaxies [ws] # ASCII table of modular architectural subsystems & coupling metrics
./scripts/omni query <prompt> [ws] [k] # Hybrid Graph-RAG architectural brief
./scripts/omni relate <src> <tgt> [t] # Inject dynamic/inferred runtime relationship edge (CALLS, ROUTES_TO)

# Ingestion & Live Watch
./scripts/omni ingest <path> [ws] # Initial one-time indexing of an untracked repository
./scripts/omni watch status # Inspect real-time file watcher sync metrics & event counters
./scripts/omni watch start [path] # Start live file watcher daemon for repository
./scripts/omni watch stop # Stop live file watcher daemon
./scripts/omni ingest <path> [ws] # Initial one-time indexing of an untracked repository
./scripts/omni watch status # Inspect real-time file watcher sync metrics & event counters
./scripts/omni watch start [path] # Start live file watcher daemon for repository
./scripts/omni watch stop # Stop live file watcher daemon
```

### 3. Tier 3: Direct REST API Endpoints Reference
Expand All @@ -199,10 +203,10 @@ All endpoints serve JSON directly from the Rust core on `http://localhost:8080`:

- `GET /api/health` — System status (`{"status":"ok","surrealdb":true,"embeddings":true}`)
- `GET /api/workspaces` — Array of indexed workspaces, node counts, languages, and live watch states
- `GET /api/symbol?name=<sym>&workspace=<ws>` — Precise symbol definition records
- `GET /api/symbol?name=<sym>&workspace=<ws>` — Precise symbol definition records (supports `Class.method` and `path:symbol`)
- `GET /api/references?symbol=<sym>&workspace=<ws>` — Callers, importers, and edge categories
- `GET /api/condense?symbol=<sym>&workspace=<ws>&hops=2` — PPR-condensed Markdown call slice
- `GET /api/search?q=<query>&workspace=<ws>&k=10&include_docs=false` — Vector similarity search
- `GET /api/search?q=<query>&workspace=<ws>&k=10&include_docs=false&exclude_tests=false&path_prefix=src/` — Vector similarity search
- `GET /api/galaxies?workspace=<ws>&limit=15` — Louvain/Leiden modular clusters and instability metrics
- `POST /api/query` — Hybrid Graph-RAG synthesis (`{"prompt":"...", "workspace":"...", "include_docs":false}`)
- `POST /api/relationships` — Edge augmentation (`{"source_symbol":"...", "target_symbol":"...", "type":"..."}`)
Expand Down
66 changes: 59 additions & 7 deletions .agents/skills/omni-graph/scripts/omni-mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,21 @@ def get_default_workspace() -> str:
TOOLS_SPEC = [
{
"name": "omni_definition",
"description": "Lookup precise AST definition, signatures, and file line ranges for a code symbol. Essential before editing code.",
"description": "Lookup precise AST definition, signatures, and file line ranges for a code symbol. Returns in-band code bodies for single targets under 120 lines to eliminate secondary read_file calls.",
"inputSchema": {
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "The exact identifier name of the function, struct, class, method, or interface."
"description": "The exact identifier name of the function, struct, class, method, or interface (supports Class.method and path:symbol)."
},
"include_body": {
"type": "boolean",
"description": "Whether to return the complete symbol body if under 120 lines (default true). Avoids secondary read_file calls."
},
"force_full_bodies": {
"type": "boolean",
"description": "Force full bodies even when query matches > 3 symbols (default false)."
},
"workspace": {
"type": "string",
Expand Down Expand Up @@ -121,6 +129,14 @@ def get_default_workspace() -> str:
"include_docs": {
"type": "boolean",
"description": "Whether to include markdown documentation nodes (default false: code-only)."
},
"exclude_tests": {
"type": "boolean",
"description": "Whether to exclude test directories and test files (default false)."
},
"path_prefix": {
"type": "string",
"description": "Filter results by directory path prefix (e.g. 'src/' or 'django_sorcery/')."
}
},
"required": ["query"]
Expand Down Expand Up @@ -201,6 +217,8 @@ def handle_tool_call(name: str, args: dict) -> dict:
try:
if name == "omni_definition":
symbol = args["symbol"]
include_body = args.get("include_body", True)
force_full_bodies = args.get("force_full_bodies", False)
params = urllib.parse.urlencode({"name": symbol, "workspace": workspace, "wait_for_sync": "true"})
res = make_http_request(f"{API_URL}/api/symbol?{params}")
if res.get("locked"):
Expand All @@ -210,11 +228,34 @@ def handle_tool_call(name: str, args: dict) -> dict:
return {"content": [{"type": "text", "text": f"Symbol '{symbol}' not found in workspace '{workspace}'."}]}

lines = [f"Found {len(matches)} match(es) for '{symbol}' in workspace '{workspace}':\n"]
match_count = len(matches)
for m in matches:
lines.append(f"• [{m.get('kind', 'symbol')}] `{m.get('label')}` in `{m.get('file_path')}:{m.get('line_start')}-{m.get('line_end')}` ({m.get('language')})")
text_preview = m.get('text', '').strip()
if text_preview:
lines.append(f" ```{m.get('language', '')}\n {text_preview[:400]}\n ```")
kind = m.get('kind', 'symbol')
label = m.get('label')
parent_prefix = f"{m.get('parent_label')}." if m.get('parent_label') else ""
disp_label = f"{parent_prefix}{label}" if parent_prefix and not label.startswith(parent_prefix) else label
refl_tag = " [⚠️ reflection]" if m.get("has_reflection") else ""
lines.append(f"• [{kind}] `{disp_label}` in `{m.get('file_path')}:{m.get('line_start')}-{m.get('line_end')}` ({m.get('language')}){refl_tag}")
text = m.get('text', '').strip()
if text:
line_start = m.get('line_start', 0)
line_end = m.get('line_end', 0)
line_count = (line_end - line_start + 1) if line_end >= line_start else len(text.splitlines())
# Adaptive budgeting (R-110):
# If single match: full body up to 120 lines / 3500 chars
# If 2-3 matches: full body up to 60 lines each
# If >3 matches and not force_full_bodies: clamp preview with guidance to prevent prompt bloat
can_embed_full = include_body and (
force_full_bodies
or (match_count == 1 and line_count <= 120 and len(text) <= 3500)
or (match_count <= 3 and line_count <= 60 and len(text) <= 2000)
)
if can_embed_full:
lines.append(f" ```{m.get('language', '')}\n{text}\n ```")
elif include_body and line_count > 120 and match_count == 1:
lines.append(f" ```{m.get('language', '')}\n{text[:600]}\n ... [truncated: {line_count} lines. Use read_file({m.get('file_path')}, StartLine={line_start}, EndLine={line_end}) for full code]\n ```")
else:
lines.append(f" ```{m.get('language', '')}\n{text[:300]} ...\n ```")
return {"content": [{"type": "text", "text": "\n".join(lines)}]}

elif name == "omni_references":
Expand Down Expand Up @@ -294,7 +335,18 @@ def handle_tool_call(name: str, args: dict) -> dict:
query = args["query"]
k = args.get("k", 10)
include_docs = "true" if args.get("include_docs", False) else "false"
params = urllib.parse.urlencode({"q": query, "workspace": workspace, "k": k, "include_docs": include_docs, "wait_for_sync": "true"})
search_query_dict = {
"q": query,
"workspace": workspace,
"k": k,
"include_docs": include_docs,
"wait_for_sync": "true",
}
if args.get("exclude_tests"):
search_query_dict["exclude_tests"] = "true"
if args.get("path_prefix"):
search_query_dict["path_prefix"] = args["path_prefix"]
params = urllib.parse.urlencode(search_query_dict)
res = make_http_request(f"{API_URL}/api/search?{params}")
if isinstance(res, dict) and res.get("locked"):
return {"content": [{"type": "text", "text": f"⏳ Workspace '{workspace}' is synchronizing graph topology. {res.get('message', '')}"}]}
Expand Down
44 changes: 30 additions & 14 deletions .agents/skills/omni-graph/scripts/omni.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ Commands:
health Check service health (Rust API, SurrealDB, TEI)
workspaces List all indexed codebases/workspaces and stats
worktrees [sync [ws]] List or sync git worktrees across parent codebases
search <query> [ws] [k] Vector similarity search (optional workspace filter)
symbol <name> [ws] Symbol definition lookup (LSP definition)
search <query> [ws] [k] [--exclude-tests|-x] [--path-prefix|-p <p>]
Dense vector similarity search (supports test exclusion and subtree filtering)
symbol <name|Class.method|path:symbol> [ws]
Symbol definition lookup (supports qualified names like Query.order_by or path:symbol)
references <symbol> [ws] Find all callers/references (LSP references)
relate <src> <tgt> [t] [ws] Augment graph with dynamic/inferred relationship
condense <sym> [ws] [hops] Multi-hop AST subgraph slice (<1500 tokens for agents)
Expand Down Expand Up @@ -97,21 +99,35 @@ except Exception as e:
;;

search)
QUERY="${1:-}"
WS="$(norm_ws "${2:-}")"
K="${3:-10}"
if [ -z "${QUERY}" ]; then echo "❌ Missing query argument"; exit 1; fi
python3 -c "
import urllib.request, urllib.parse, json, sys
params = {'q': sys.argv[1], 'k': sys.argv[3]}
if sys.argv[2]:
params['workspace'] = sys.argv[2]
import argparse, json, sys, urllib.parse, urllib.request

parser = argparse.ArgumentParser(prog='omni search', description='Vector similarity search')
parser.add_argument('query', help='Search query')
parser.add_argument('workspace', nargs='?', default=None, help='Workspace filter')
parser.add_argument('k', nargs='?', default=10, type=int, help='Top k results')
parser.add_argument('--exclude-tests', '-x', action='store_true', help='Exclude test files')
parser.add_argument('--path-prefix', '-p', default=None, help='Filter by file path prefix')

args = parser.parse_args([a for a in sys.argv[1:] if a != ''])
params = {'q': args.query, 'k': str(args.k)}
if args.workspace:
params['workspace'] = args.workspace.rstrip('/').split('/')[-1]
if args.exclude_tests:
params['exclude_tests'] = 'true'
if args.path_prefix:
params['path_prefix'] = args.path_prefix

url = '${ENDPOINT}/api/search?' + urllib.parse.urlencode(params)
req = urllib.request.Request(url)
with urllib.request.urlopen(req) as resp:
data = json.loads(resp.read().decode())
print(json.dumps(data, indent=2))
" "${QUERY}" "${WS}" "${K}"
try:
with urllib.request.urlopen(req) as resp:
data = json.loads(resp.read().decode())
print(json.dumps(data, indent=2))
except Exception as e:
print(f'❌ Search failed: {e}', file=sys.stderr)
sys.exit(1)
" "$@"
;;

symbol)
Expand Down
Loading
Loading