Files
claw-code/docs/gjc-compat/tool-semantics-phase1.md
clawdbot 30f607e03a Implement :conflicts selector for read_file tool
- Add real git merge conflict extraction matching GJC behavior
- Extract unresolved conflict blocks (<<<<<<, =======, >>>>>>>)
- Support 3-way conflicts with diff3 markers (|||||||)
- Format conflicts as indexed summary with line ranges and labels
- Return clear 'No unresolved git merge conflicts' when clean
- Add comprehensive behavior tests for 2-way, 3-way, and no-conflicts cases
- Update documentation to mark :conflicts as implemented
- Closes #3323

Tests:
- read_with_selector_conflicts_no_conflicts: verifies clean file message
- read_with_selector_conflicts_two_way: verifies multiple conflict detection
- read_with_selector_conflicts_three_way: verifies diff3 marker support
2026-10-12 23:57:50 +00:00

9.4 KiB

GJC Tool Semantics Alignment: Phase 1 (read/edit/search/find)

Status: Implementation plan
Issue: #3323
Scope: Slice 2.1 - Tool catalog semantic parity for read/edit/search/find
Target: Ship in batches with focused PRs


1. EXECUTIVE SUMMARY

This document details the semantic gaps between claw-code's current tool implementations and GJC's (gajae-code) reference implementations for the highest-value tools: read, edit, search, and find.

Key Gaps

Tool Current (claw-code) Target (GJC) Gap Complexity
read offset/limit pagination Line selectors (:L-L+N), raw mode, truncation footers High Medium
write Simple file replacement Full replacement semantics (matching GJC) Low Low
edit String replacement (old→new) String replacement with rich patch output Low Low
find (glob) Pattern expansion only Recursive glob with filtering Low Low
search (grep) Regex search with context Regex with context + advanced filtering Low Low

2. GJC TOOL SEMANTICS REFERENCE

2.1 READ Tool

Source: gajae-code/packages/coding-agent/src/tools/read.ts (3,500+ LOC)

Input Schema

{
  path: string;           // File path (relative or absolute)
  offset?: number;        // Line offset (for pagination)
  limit?: number;         // Lines to read (for pagination)
  // GJC extensions (missing in claw-code):
  selector?: string;      // Line range syntax:
                          // ":50" = line 50 onward
                          // ":50-200" = lines 50-200 inclusive
                          // ":50+150" = 150 lines starting at line 50
                          // ":raw" = full file verbatim
                          // ":conflicts" = git merge conflicts only
  truncationDirection?: "head" | "tail" | "both";  // Which end to keep
  maxSummaryBytes?: number;  // Summary budget (default 50KB)
  maxSummaryLines?: number;  // Summary budget (default 20K lines)
}

Output Structure

{
  "file": {
    "path": "src/main.rs",
    "content": "...",
    "totalLines": 500,
    "totalBytes": 12345,
    "truncatedBy": "lines" | "bytes" | "middle" | null,
    "displayMode": "summarized" | "raw" | "receipt"
  },
  "truncationFooter": "[Showing lines 1-50 of 500; re-read ...]"
}

Key Behaviors

  1. Line Range Selectors (:selector syntax)

    • :50 = start at line 50
    • :50-200 = lines 50-200 inclusive
    • :50+150 = 150 lines starting at 50
    • :50+1 = exactly one line
    • :5-16,960-973 = multiple ranges
    • :raw = full verbatim
    • :conflicts = git merge conflicts
  2. Truncation Modes

    • Default: 50KB bytes limit, 20K lines limit
    • Direction: head (keep start), tail (keep end), both (keep both ends)
    • Footer includes recovery hint (e.g., "re-read path:1-9999 for verbatim")
  3. Structural Summarization

    • Code: collapse function bodies to .. or … (merged brace pairs)
    • Prose: preserve full lines, truncate at word boundaries
    • Special files: documents (PDF, DOCX, XLSX) converted via markit
  4. Archive Support

    • .tar, .tar.gz, .tgz, .zip: member read with archive.ext:path/inside
    • SQLite: .sqlite:table or .sqlite:table:key queries
    • Line ranges apply to archive members
  5. Output Formatting

    • Anchored output: Line prefixes with source line numbers and hash anchors
    • Optional hash lines: Marks structural boundaries (# pragma, function start, etc.)
    • Prose column cap: Long lines wrapped/truncated at column limit

2.2 EDIT Tool

Source: gajae-code/packages/coding-agent/src/tools/edit.ts

Input Schema

{
  path: string;           // File to edit
  old_text: string;       // Text to replace (required for edit)
  new_text: string;       // Replacement text
  all?: boolean;          // Replace all occurrences (default: first only)
}

Output Structure

{
  "file": {
    "path": "src/main.rs",
    "editCount": 1,
    "beforeSize": 12345,
    "afterSize": 12400
  },
  "patch": [
    {
      "type": "replace",
      "lineStart": 50,
      "lineEnd": 55,
      "before": "old content",
      "after": "new content",
      "context": {"before": 3, "after": 3}
    }
  ]
}

Key Behaviors

  1. Exact Match Required: old_text must match exactly (no fuzzy matching)
  2. Smallest Replacement: Use smallest unique old_text that identifies the change
  3. All-or-Nothing: Either all occurrences replaced or none (no partial)
  4. Patch Metadata: Line numbers, context, before/after preserved

2.3 SEARCH Tool

Source: gajae-code/packages/coding-agent/src/tools/search.ts

Input Schema

{
  pattern: string;        // Regex pattern
  paths?: string[];       // Files/dirs to search
  context?: number;       // Context lines before/after (default: 2)
  i?: boolean;            // Case-insensitive
  glob_exclude?: string[];  // Patterns to skip
  file_type?: string;     // Filter by extension
  limit?: number;         // Max results
  truncation?: "head" | "tail" | "both";
}

Output Structure

{
  "matches": [
    {
      "file": "src/main.rs",
      "lineNumber": 42,
      "line": "fn process() {",
      "before": ["// Process data", ""],
      "after": ["  // Implementation", ""]
    }
  ],
  "summary": "Found 5 matches in 3 files"
}

2.4 FIND Tool

Source: gajae-code/packages/coding-agent/src/tools/find.ts

Input Schema

{
  paths: string[];        // Glob patterns
  timeout?: number;       // Timeout in seconds (default: 5)
  gitignore?: boolean;    // Respect .gitignore (default: true)
  hidden?: boolean;       // Include hidden files (default: true)
  limit?: number;         // Max results (default: 1000)
}

Output Structure

{
  "files": [
    {
      "path": "src/main.rs",
      "modified": "2026-10-13T12:34:56Z",
      "size": 12345
    }
  ],
  "summary": "Found 42 files matching pattern",
  "truncated": false
}

3. CURRENT CLAW-CODE IMPLEMENTATION GAPS

3.1 READ Tool Gaps

File: rust/crates/runtime/src/file_ops.rs:713

Current:

pub fn read_file_in_workspace(
    path: &str,
    offset: Option<usize>,     // Line offset only
    limit: Option<usize>,      // Lines only
    workspace_root: &Path,
) -> io::Result<ReadFileOutput>

Missing:

  • ✗ Line range selectors (:L-L+N syntax)
  • ✗ Raw mode (:raw)
  • ✓ Git merge conflict extraction (:conflicts)
  • ✗ Truncation footers with recovery hints
  • ✗ Structural summarization (collapse braces)
  • ✗ Archive/SQLite support
  • ✗ Multi-range selectors (:5-16,960-973)
  • ✗ Prose column cap
  • ✗ Hash line anchors

Estimated LOC to Add: 1,200-1,500 (including tests)

3.2 EDIT Tool Gaps

File: rust/crates/runtime/src/file_ops.rs:760

Current: Basic string replacement works
Missing:

  • ✗ Rich patch metadata (line numbers, context lines)

Estimated LOC to Add: 200-300

3.3 SEARCH Tool Gaps

File: rust/crates/tools/src/lib.rs (grep search)

Current: Basic regex with context
Missing:

  • ✗ Advanced filtering (file type, glob exclude)
  • ✗ Structured output format

Estimated LOC to Add: 300-400

3.4 FIND Tool Gaps

File: rust/crates/tools/src/lib.rs (glob search)

Current: Basic glob expansion
Missing:

  • ✗ Recursive globs
  • ✗ Gitignore filtering
  • ✗ Hidden file control
  • ✗ File metadata

Estimated LOC to Add: 200-300


4. IMPLEMENTATION PLAN (BATCHED)

Batch 1: READ Tool (Priority P0)

  • Add line range selector parsing
  • Implement :raw mode
  • ✓ Implement :conflicts mode
  • Add truncation footers with recovery hints
  • Implement structural summarization
  • Add tests for all selector combinations

Files to Modify:

  • rust/crates/runtime/src/file_ops.rs (read_file_in_workspace)
  • rust/crates/tools/src/lib.rs (ReadFileInput struct)
  • Tests in both

Size Estimate: 1,200 LOC
Complexity: Medium (string parsing, output formatting)

Batch 2: EDIT Tool (Priority P1)

  • Add patch metadata to output
  • Ensure exact match semantics
  • Add comprehensive tests

Files to Modify:

  • rust/crates/runtime/src/file_ops.rs (edit_file_in_workspace)
  • Tests

Size Estimate: 200 LOC
Complexity: Low

Batch 3: SEARCH/FIND Tools (Priority P1)

  • Enhance grep/find with GJC-compatible filtering
  • Add structured output format
  • Add metadata (file type, modified time)

Files to Modify:

  • rust/crates/tools/src/lib.rs (glob_search, grep_search)
  • rust/crates/runtime/src/file_ops.rs

Size Estimate: 500 LOC
Complexity: Low-Medium


5. VERIFICATION STRATEGY

Each batch will include:

  1. Semantic Tests: Verify tool inputs/outputs match GJC reference
  2. Edge Case Tests: Line ranges, truncation, archives, etc.
  3. Integration Tests: End-to-end with claw CLI
  4. Parity Shadow Test: Run same inputs against both GJC and claw-code, compare outputs

6. ROLLOUT SCHEDULE

  • Batch 1 (READ): Week 1 - Enable most impactful tool first
  • Batch 2 (EDIT): Week 1-2 - Quick follow-up
  • Batch 3 (SEARCH/FIND): Week 2 - Lower priority but valuable for discoverability

7. REFERENCES

  • GJC Read Tool: /home/bellman/Workspace/gajae-code/packages/coding-agent/src/tools/read.ts
  • claw-code file_ops: rust/crates/runtime/src/file_ops.rs
  • claw-code tools: rust/crates/tools/src/lib.rs
  • Gap Matrix: docs/gjc-compat/gap-matrix.md