Feature: search CLI --output=json + per-file aggregation #6

Closed
opened 2026-02-16 04:15:06 -05:00 by yindo · 3 comments
Owner

Originally created by @lwyBZss8924d on GitHub (Sep 18, 2025).

Summary

Add a machine-readable JSON output mode and per-file aggregation flags to the search CLI to support agentic orchestrations (e.g., hierarchical navigation RAG) without brittle text parsing.

Motivation

  • Many agent/orchestrator flows (e.g., Cookbook-style "split → route → drill down → cite → synthesize → verify") need stable, structured output to post-process results automatically.
  • Current search prints human-readable text only (filename:start::end (distance) + context lines). Parsing this in scripts is fragile.
  • JSON output enables robust downstream processing via jq and other tools and simplifies multi-depth routing used by retrieval agents.

Proposed CLI changes (non-breaking)

  • New flag: --output <text|json> (default: text). When json, emit a single JSON object to stdout.
  • New flags for result shaping:
    • --aggregate-by <file|none> (default: none) – when file, group matches by file and pick the top-N per file.
    • --limit-per-file <N> (default: 1 when aggregate-by=file; otherwise ignored) – per-file cap for grouped results.
  • Optional: --pretty to pretty-print json (default: compact).

JSON schema (draft)

{
  "query": "<string>",
  "params": {
    "n_lines": <int>,
    "top_k": <int>,
    "max_distance": <float|null>,
    "ignore_case": <bool>
  },
  "matches": [
    {
      "file": "<string>",
      "start": <int>,
      "end": <int>,
      "match_line": <int>,
      "distance": <float>,
      "lines": ["<string>"]
    }
  ]
}

Examples

  • Text (unchanged default):
    search "installation, setup" -i --n-lines 4 --max-distance 0.35 docs/**/*.md
    
  • JSON:
    search "installation, setup" -i --n-lines 4 --max-distance 0.35 --output json docs/**/*.md | jq '.matches[0]'
    
  • Aggregated per file (top 2 per file):
    search "api token, oauth2" --output json --aggregate-by file --limit-per-file 2 docs/**/*.md
    

Backward compatibility

  • Default output stays as text; no breakage for existing users and scripts.

Implementation notes

  • Update clap options in src/bin/search.rs.
  • Introduce serializable structs (e.g., JsonMatch, JsonResult) and emit via serde_json.
  • Keep existing workspace/non-workspace flows; JSON is just a different printer layer.

Acceptance criteria

  • --output text remains the default and identical to current behavior.
  • --output json returns valid JSON for both workspace and non-workspace modes.
  • --aggregate-by file + --limit-per-file works as described.
  • README updated with examples; basic tests added for JSON mode.

Related context

  • Designed to support hierarchical-navigation retrieval agents (e.g., ACPLazyBridge document-retriever) and Cookbook-style Long-Context RAG without pre-embedded indices.
Originally created by @lwyBZss8924d on GitHub (Sep 18, 2025). ## Summary Add a machine-readable JSON output mode and per-file aggregation flags to the `search` CLI to support agentic orchestrations (e.g., hierarchical navigation RAG) without brittle text parsing. ## Motivation - Many agent/orchestrator flows (e.g., Cookbook-style "split → route → drill down → cite → synthesize → verify") need stable, structured output to post-process results automatically. - Current `search` prints human-readable text only (filename:start::end (distance) + context lines). Parsing this in scripts is fragile. - JSON output enables robust downstream processing via jq and other tools and simplifies multi-depth routing used by retrieval agents. ## Proposed CLI changes (non-breaking) - New flag: `--output <text|json>` (default: text). When `json`, emit a single JSON object to stdout. - New flags for result shaping: - `--aggregate-by <file|none>` (default: none) – when `file`, group matches by file and pick the top-N per file. - `--limit-per-file <N>` (default: 1 when aggregate-by=file; otherwise ignored) – per-file cap for grouped results. - Optional: `--pretty` to pretty-print json (default: compact). ## JSON schema (draft) ```json { "query": "<string>", "params": { "n_lines": <int>, "top_k": <int>, "max_distance": <float|null>, "ignore_case": <bool> }, "matches": [ { "file": "<string>", "start": <int>, "end": <int>, "match_line": <int>, "distance": <float>, "lines": ["<string>"] } ] } ``` ## Examples - Text (unchanged default): ```bash search "installation, setup" -i --n-lines 4 --max-distance 0.35 docs/**/*.md ``` - JSON: ```bash search "installation, setup" -i --n-lines 4 --max-distance 0.35 --output json docs/**/*.md | jq '.matches[0]' ``` - Aggregated per file (top 2 per file): ```bash search "api token, oauth2" --output json --aggregate-by file --limit-per-file 2 docs/**/*.md ``` ## Backward compatibility - Default output stays as text; no breakage for existing users and scripts. ## Implementation notes - Update clap options in `src/bin/search.rs`. - Introduce serializable structs (e.g., `JsonMatch`, `JsonResult`) and emit via `serde_json`. - Keep existing workspace/non-workspace flows; JSON is just a different printer layer. ## Acceptance criteria - `--output text` remains the default and identical to current behavior. - `--output json` returns valid JSON for both workspace and non-workspace modes. - `--aggregate-by file` + `--limit-per-file` works as described. - README updated with examples; basic tests added for JSON mode. ## Related context - Designed to support hierarchical-navigation retrieval agents (e.g., ACPLazyBridge document-retriever) and Cookbook-style Long-Context RAG without pre-embedded indices.
yindo closed this issue 2026-02-16 04:15:06 -05:00
Author
Owner

@lwyBZss8924d commented on GitHub (Sep 18, 2025):

Intent: empower agentic, hierarchical navigation loops (split → route → drill down → cite → verify) without pre-indexing. Agents need stable, programmatic outputs to autonomously select, de-duplicate, and refine evidence across multiple passes.

Why JSON + per-file aggregation matters:

  • JSON removes brittle text parsing so routers can consume results deterministically (file, start, end, match_line, distance, lines).
  • --aggregate-by file + --limit-per-file enables coarse routing (pick strongest signal per document), then drill down on a narrowed set at the next depth.
  • This mirrors Cookbook-style hierarchical progressive navigation and drastically simplifies scratchpad logging, citation formatting (file:start::end), and verification.

Scope and safety:

  • Purely a printer/result-shaping layer; no change to core search semantics.
  • Backward compatible (default text unchanged), works with and without workspace.

Outcome:

  • Makes SemTools a first-class building block for autonomous retrieval agents that must reason over long documents with coarse→fine passes and produce verifiable, paragraph/line-level citations.
@lwyBZss8924d commented on GitHub (Sep 18, 2025): Intent: empower agentic, hierarchical navigation loops (split → route → drill down → cite → verify) without pre-indexing. Agents need stable, programmatic outputs to autonomously select, de-duplicate, and refine evidence across multiple passes. Why JSON + per-file aggregation matters: - JSON removes brittle text parsing so routers can consume results deterministically (file, start, end, match_line, distance, lines). - --aggregate-by file + --limit-per-file enables coarse routing (pick strongest signal per document), then drill down on a narrowed set at the next depth. - This mirrors Cookbook-style hierarchical progressive navigation and drastically simplifies scratchpad logging, citation formatting (file:start::end), and verification. Scope and safety: - Purely a printer/result-shaping layer; no change to core search semantics. - Backward compatible (default text unchanged), works with and without workspace. Outcome: - Makes SemTools a first-class building block for autonomous retrieval agents that must reason over long documents with coarse→fine passes and produce verifiable, paragraph/line-level citations.
Author
Owner

@lwyBZss8924d commented on GitHub (Sep 18, 2025):

Reference: OpenAI Model Selection Guide — Long-Context Agentic RAG

Relevant takeaways for this proposal:

  • Context window is a superpower: million-token windows enable on-the-fly navigation (no preprocessing/indexing).
  • Hierarchical approach mimics human reading: coarse routing → focused drill-down → paragraph-level citations.
  • Scratchpad enables multi-step reasoning and transparent routing decisions.
  • Fast implementation, no database: structured IO + API calls suffice.
  • Verification improves reliability: LLM-as-judge over cited paragraphs.

Why this matters for --output=json + per-file aggregation:

  • JSON gives agents deterministic fields (file, start, end, match_line, distance, lines) for autonomous hierarchical routing.
  • Per-file aggregation lets agents pick the strongest evidence per document at depth-0, then recursively refine at depth-1/2 (Cookbook-style).

Agent example (excerpt) using SemTools as the retrieval backbone:

---
name: document-retriever
model: opus
---
# Tools: workspace, parse, search (+ fd/rg/jq)
# Operating Principles: non-interactive, avoid stdin, threshold-first (--max-distance 0.35, --n-lines 4), adaptive ladder, run artifacts with workspace status.
# Hierarchical Navigation: depth-0 coarse route → depth-1 drill-down → depth-2 paragraph-level; citations file:start::end; scratchpad logging; LLM-as-judge verification.

JSON output directly supports this autonomous loop (split → route → drill → cite → verify) by eliminating brittle parsing and making multi-depth selection/merging straightforward.

@lwyBZss8924d commented on GitHub (Sep 18, 2025): Reference: OpenAI Model Selection Guide — Long-Context Agentic RAG - https://cookbook.openai.com/examples/partners/model_selection_guide/model_selection_guide#7-takeaways Relevant takeaways for this proposal: - Context window is a superpower: million-token windows enable on-the-fly navigation (no preprocessing/indexing). - Hierarchical approach mimics human reading: coarse routing → focused drill-down → paragraph-level citations. - Scratchpad enables multi-step reasoning and transparent routing decisions. - Fast implementation, no database: structured IO + API calls suffice. - Verification improves reliability: LLM-as-judge over cited paragraphs. Why this matters for `--output=json` + per-file aggregation: - JSON gives agents deterministic fields (file, start, end, match_line, distance, lines) for autonomous hierarchical routing. - Per-file aggregation lets agents pick the strongest evidence per document at depth-0, then recursively refine at depth-1/2 (Cookbook-style). Agent example (excerpt) using SemTools as the retrieval backbone: ```yaml --- name: document-retriever model: opus --- # Tools: workspace, parse, search (+ fd/rg/jq) # Operating Principles: non-interactive, avoid stdin, threshold-first (--max-distance 0.35, --n-lines 4), adaptive ladder, run artifacts with workspace status. # Hierarchical Navigation: depth-0 coarse route → depth-1 drill-down → depth-2 paragraph-level; citations file:start::end; scratchpad logging; LLM-as-judge verification. ``` JSON output directly supports this autonomous loop (split → route → drill → cite → verify) by eliminating brittle parsing and making multi-depth selection/merging straightforward.
Author
Owner

@logan-markewich commented on GitHub (Sep 18, 2025):

Great idea! Would be very open to adding a json output mode to search

@logan-markewich commented on GitHub (Sep 18, 2025): Great idea! Would be very open to adding a `json` output mode to search
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: run-llama/semtools#6