{
  "shell.native_background": {
    "score": 1,
    "evidence": "First-class background path: model-facing `is_background` flag at crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:292-306; background branch calls backend.run_background and returns BackgroundTaskStarted with a task_id at crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:1984-2067. Backgrounding is on by default (BashParams.enabled_background=true, crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:164-165,210-224)."
  },
  "shell.timeout_cap": {
    "score": 1,
    "evidence": "Model-settable `timeout` with documented default 120000 ms and hard maxima: crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:266-284 (schema), 475-476 (DEFAULT_MAX_TIMEOUT_MS 300000, ABSOLUTE_MAX_TIMEOUT_MS 10h), 1219-1292 (clamping). Production opt-up is explicit: crates/codegen/xai-grok-shell/src/tools/config.rs:7-12 and 56-60 send max_timeout_secs=36000 (10h)."
  },
  "shell.persistent": {
    "score": 0.5,
    "evidence": "State-replaying persistent shell exists: crates/codegen/xai-grok-tools/src/computer/local/shell_state.rs:1-17 (env/cwd/functions/aliases dumped and replayed per call) and crates/codegen/xai-grok-tools/src/computer/local/terminal.rs:762-900 (spawn_persistent_command). But it is off by default: LocalTerminalConfig::default persistent_shell=false at crates/codegen/xai-grok-tools/src/computer/local/terminal.rs:2252-2258, and the default local backend selection is LocalNonPersistent at crates/codegen/xai-grok-shell/src/session/acp_session_impl/spawn.rs:2663-2678."
  },
  "shell.powershell": {
    "score": 1,
    "evidence": "PowerShell is a first-class shell: Windows shell cascade pwsh -> powershell.exe -> Git Bash -> cmd at crates/codegen/xai-grok-config/src/shell.rs:1-10 and 70-95; argv construction for Pwsh/PowerShell at crates/codegen/xai-grok-config/src/shell.rs:285-330; shell-aware ampersand rules and PowerShell remediation at crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:559-608, 1530-1548."
  },
  "shell.middle_out": {
    "score": 1,
    "evidence": "Middle-out truncation keeps both ends: crates/codegen/xai-grok-tools/src/computer/local/terminal.rs:386-412 freezes the front half in front_buffer and keeps the tail; ring_output re-joins them with FRONT_BACK_TRUNCATION_MARKER at crates/codegen/xai-grok-tools/src/computer/local/terminal.rs:486-495. The model-visible annotation says 'showing first/last' at crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:403-411."
  },
  "shell.full_log": {
    "score": 1,
    "evidence": "Every command writes to a session log file, and the truncation annotation returns its path: output file built at crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:1980-1982, attached to BashOutput at crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:2206-2217, and printed as 'full output at: <path>' at crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:405-411."
  },
  "shell.omitted_counts": {
    "score": 0.5,
    "evidence": "Recovery is given and both sizes are shown ('[truncated: showing first/last {} of {} - full output at: {}]', crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:405-411), but the amount omitted is never stated: only shown bytes and total bytes, leaving subtraction to the model. Searched for an explicit omitted count/line count; none exists in the bash truncation path."
  },
  "shell.signal_honesty": {
    "score": 0.5,
    "evidence": "Signal death is not faked as success, but it is not reported as 128+N either. extract_exit_status yields exit_code=None and signal='signal N' (crates/codegen/xai-grok-tools/src/computer/local/terminal.rs:3290-3303); format_default_prompt renders 'exit: killed (signal 15)' (crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:451-459). Only cgroup OOM is special-cased to exit 137 (crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:3539-3550); ordinary SIGTERM/SIGKILL never become 143/137."
  },
  "shell.benign_exit": {
    "score": 0,
    "evidence": "Searched for grep/diff/test exit-1 annotations. The only bash annotations are truncation and signal (crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:403-421); a real non-zero exit renders bare 'exit: 1' (asserted by default_prompt_real_exit_code_unchanged at crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:3539-3545). No benign-exit mapping in the bash or task-output paths."
  },
  "shell.untrusted_fencing": {
    "score": 0,
    "evidence": "Foreground output is not delimited: format_default_prompt emits 'exit: N\\n<raw output>' with no fence or data envelope (crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:429-460), and the default-prompt test explicitly asserts the output contains no code fence (crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:3465-3476). Only the backgrounded variant wraps the partial output in ``` fences (crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:441-449)."
  },
  "shell.bg_output_reader": {
    "score": 1,
    "evidence": "Model-facing reader exists: get_task_output / get_command_or_subagent_output returns current output, status and exit code for a task id. Input at crates/common/xai-tool-types/src/task.rs:519-555; snapshot path at crates/codegen/xai-grok-tools/src/implementations/grok_build/task_output/mod.rs:190-240; registered in the default toolset as get_command_or_subagent_output (crates/codegen/xai-grok-agent/src/config.rs:159-161)."
  },
  "shell.wait_modes": {
    "score": 0.5,
    "evidence": "Two of three modes: omit timeout_ms/0 is a non-blocking snapshot ('now'), positive timeout_ms waits for completion ('exit') at crates/common/xai-tool-types/src/task.rs:577-583 and crates/codegen/xai-grok-tools/src/implementations/grok_build/task_output/mod.rs:199-211. There is no 'wait for new output' mode: the only wait primitive is terminal.wait_for_completion, and the input has no output-cursor/pattern parameter."
  },
  "shell.cursor_reads": {
    "score": 0,
    "evidence": "Searched for byte-offset/delta reads. The model-facing task-output input is only task_ids + timeout_ms (crates/common/xai-tool-types/src/task.rs:519-555); each call rebuilds a full TaskSnapshot from ring_output (crates/codegen/xai-grok-tools/src/computer/local/terminal.rs:359-378, 447-484). output_delta exists only for the TUI (crates/codegen/xai-grok-tools/src/types/output.rs:434-440) and is always None in the bash tool (crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:2218)."
  },
  "shell.list_tasks": {
    "score": 0,
    "evidence": "Searched the registry and tool implementations for a model-invoked live-task listing. The registered toolset has no list-tasks tool (crates/codegen/xai-grok-tools/src/registry/types.rs:685-720); task IDs are only enumerated opportunistically inside not-found errors (crates/codegen/xai-grok-tools/src/implementations/grok_build/kill_task/mod.rs:47-70, crates/codegen/xai-grok-tools/src/implementations/grok_build/task_output/mod.rs:255-270)."
  },
  "shell.kill_id": {
    "score": 1,
    "evidence": "Model-facing kill_task / kill_command_or_subagent takes a task_id and resolves it against the terminal backend: input at crates/common/xai-tool-types/src/task.rs:760-763; cancellation path at crates/codegen/xai-grok-tools/src/implementations/grok_build/kill_task/mod.rs:52-56, 150-200; registered by default as kill_command_or_subagent (crates/codegen/xai-grok-agent/src/config.rs:166-169)."
  },
  "shell.kill_pid_port": {
    "score": 0,
    "evidence": "Searched for pid/port kill inputs. KillTaskToolInput is a single `task_id` string (crates/common/xai-tool-types/src/task.rs:760-763), and no other registered tool accepts a raw pid or listening port (tool IDs enumerated at crates/codegen/xai-grok-tools/src/implementations/grok_build/kill_task/mod.rs:161-162 and crates/codegen/xai-grok-tools/src/implementations/grok_build/task_output/mod.rs:889-890). Raw `kill` is only reachable by shelling out through bash."
  },
  "shell.sigterm_escalation": {
    "score": 1,
    "evidence": "Explicit graceful-then-force kill: graceful_kill_and_wait sends SIGTERM to the group, waits SIGTERM_GRACE (1s), then sends SIGKILL at crates/codegen/xai-grok-tools/src/computer/local/terminal.rs:2861-2890; grace constant at crates/codegen/xai-grok-tools/src/computer/local/terminal.rs:42-43. The tool description also advertises SIGTERM -> SIGKILL after ~1s (crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:1481)."
  },
  "shell.group_kill": {
    "score": 1,
    "evidence": "Process groups are validated before killpg: ProcessGroupId::new rejects pgid 0, 1, the caller's own pgid, and values beyond i32::MAX, so killpg can only reach a real foreign group (crates/codegen/xai-tty-utils/src/lib.rs:593-638); attach stores the validated id (crates/codegen/xai-tty-utils/src/lib.rs:721-762). Terminal children are spawned detached and enrolled via ProcessGroup::attach (crates/codegen/xai-grok-tools/src/computer/local/terminal.rs:3200-3260, 739-742), and the group is dropped at reap (crates/codegen/xai-grok-tools/src/computer/local/terminal.rs:1415-1425, 2917-2925)."
  },
  "shell.monitor": {
    "score": 1,
    "evidence": "A first-class monitor tool wakes the agent on output instead of polling: each stdout line is an event/wake (description at crates/codegen/xai-grok-tools/src/implementations/grok_build/monitor/tool.rs:31-40), runs the command as a background terminal task and emits MonitorEvent notifications (crates/codegen/xai-grok-tools/src/implementations/grok_build/monitor/tool.rs:96-140). It is in the default grok-build toolset (crates/codegen/xai-grok-agent/src/config.rs:274-300)."
  },
  "shell.sleep": {
    "score": 0,
    "evidence": "Searched the registered toolset for a sleep/park tool. There is no Sleep tool id among the registered implementations (crates/codegen/xai-grok-tools/src/registry/types.rs:685-720); the scheduler error text only steers models away from sleeping (crates/codegen/xai-grok-tools/src/implementations/grok_build/scheduler/create.rs:360-372). No wake-on-user-input parking primitive exists."
  },
  "shell.cron": {
    "score": 1,
    "evidence": "Durable scheduling exists: scheduler_create takes an interval + prompt and a `durable` flag (crates/codegen/xai-grok-tools/src/implementations/grok_build/scheduler/create.rs:24-55), ScheduledTask carries `durable` (crates/codegen/xai-grok-tools/src/implementations/grok_build/scheduler/types.rs:200-270), and the actor persists/replays occurrences across restart (crates/codegen/xai-grok-tools/src/implementations/grok_build/scheduler/actor.rs:1355-1420). Create/Delete/List are in the default toolset (crates/codegen/xai-grok-agent/src/config.rs:274-300)."
  },
  "shell.bg_subagents": {
    "score": 1,
    "evidence": "Background subagents are the default: ACP SubagentInput.run_in_background defaults true (crates/common/xai-tool-types/src/task.rs:33-44), the task tool returns immediately on the background branch (crates/codegen/xai-grok-tools/src/implementations/grok_build/task/mod.rs:557-603), and results are collected with get_task_output/get_command_or_subagent_output (crates/common/xai-tool-types/src/task.rs:519-555)."
  },
  "shell.safe_classification": {
    "score": 0,
    "evidence": "Searched for AST/tree-sitter bash parsing. Classification is not syntax-based: permission rules match command globs/prefixes (crates/codegen/xai-grok-workspace/src/permission/policy.rs:760-770) and auto mode uses an LLM/heuristic classifier (crates/codegen/xai-grok-shell/src/util/config/resolve/auto_mode.rs:1-30). No AST or shell-grammar command classifier exists."
  },
  "shell.workspace_boundary": {
    "score": 0.5,
    "evidence": "A kernel-enforced workspace boundary exists in the sandbox (profiles workspace/read-only/strict, crates/codegen/xai-grok-sandbox/src/profiles.rs:1-10), but it is off in the default configuration: SandboxSettingsConfig::resolve_profile defaults to \"off\" at crates/codegen/xai-grok-shell/src/agent/config.rs:1189-1200. The bash tool itself performs no outside-workspace path check (crates/codegen/xai-grok-tools/src/implementations/grok_build/bash/mod.rs:1971-1982 runs the command verbatim)."
  },
  "read.line_window": {
    "score": 1,
    "evidence": "Default bounded window of 1000 lines: MAX_LINES_READ=1000 at crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:56-57, default cap in TruncationConfig at crates/codegen/xai-grok-tools/src/types/context.rs:3,35, and the effective limit is min(model limit, max_lines) at crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:495-507."
  },
  "read.second_ceiling": {
    "score": 1,
    "evidence": "A second ceiling beyond the line window: the extracted window is token-estimated and rejected with FileTooLarge above MAX_NUM_TOKENS=25_000 at crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:56,515-562. This fires even when the model supplies its own offset/limit."
  },
  "read.per_line_clamp": {
    "score": 0,
    "evidence": "No per-line clamp in the default reader: the code explicitly states 'grok_build read_file never clips lines' (crates/codegen/xai-grok-tools/src/types/context.rs:65-74), and extract_file_content_lines writes each line verbatim (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:258-294). A single huge line is only handled by a 25k-token error suggesting bash (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:530-540)."
  },
  "read.line_prefixes": {
    "score": 0.5,
    "evidence": "Line numbers are truthful 1-indexed values but only prefixed on the first returned line and every 10th line: crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:283-292 (`if is_first_visible || line_num.is_multiple_of(10)`), with the anchor convention documented at crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:108-109. Intermediate lines have no prefix, so not every prefix agrees with cat -n."
  },
  "read.resume_offset": {
    "score": 0,
    "evidence": "Searched for a truncation/resume note in the default reader. FileContent renders content only (crates/codegen/xai-grok-tools/src/types/output.rs:712-730 returns file_content.content), and read_file returns offset/limit metadata but appends no 'Showing lines X-Y of Z; use offset=N' footer (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:584-593). The only such footer is in the non-default opencode reader (crates/codegen/xai-grok-tools/src/implementations/opencode/read/mod.rs:334-338)."
  },
  "read.empty_file_note": {
    "score": 1,
    "evidence": "An empty file renders an explicit 'File is empty.' notice instead of blank output: crates/codegen/xai-grok-tools/src/types/output.rs:712-714, asserted by read_empty_file_prompt_says_file_is_empty at crates/codegen/xai-grok-tools/src/types/output.rs:1470-1476."
  },
  "read.eof_note": {
    "score": 1,
    "evidence": "An empty window past the end of the file is reported as a notice, not an error: 'FileContent { total_lines > 0, offset > total_lines }' maps to '(no lines returned: the requested window is past the end of the file; the file has N lines)' at crates/codegen/xai-grok-tools/src/types/output.rs:715-725, tested at crates/codegen/xai-grok-tools/src/types/output.rs:1476-1494."
  },
  "read.streaming": {
    "score": 0,
    "evidence": "Searched for a memory-capped streaming read. The reader loads the whole file into a Vec<u8> first: fs.read_file at crates/codegen/xai-grok-tools/src/computer/local/file_system.rs:133-145 calls fs::read, and run_read_file materializes the entire file before any windowing (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:381-433). Only the projection to the client is streamed (READ_FILE_CAPABILITIES, crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:65-77)."
  },
  "read.deferred_chunk": {
    "score": 0,
    "evidence": "Searched for deferred chunk-boundary truncation. The reader has no 'more remains' claim at all: it returns exactly the selected window with no truncation footer (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:509-593), and the generic preview truncator is a separate helper not used by read_file (crates/codegen/xai-grok-tools/src/util/truncate.rs:135-158)."
  },
  "read.dedup": {
    "score": 0,
    "evidence": "Searched for unchanged-read dedup/stub behavior in the read tool and session layer. Every call returns full extracted content (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:584-593); FileStateTracker is a rewind snapshot store, not a read-result cache (crates/codegen/xai-grok-shell/src/session/acp_session_impl/spawn.rs:599-603). No hash-of-window short-circuit exists."
  },
  "read.ledger": {
    "score": 0,
    "evidence": "Searched for a read-before-write ledger. The only related knob is a deprecated no-op: skip_read_before_edit is documented as a runtime no-op that only gates a config-time Read-tool requirement (crates/codegen/xai-grok-tools/src/implementations/grok_build/search_replace/mod.rs:96-110). Writes do not consult what the model has read; on old_string misses they only append a 'the file may have changed' hint (crates/codegen/xai-grok-tools/src/implementations/grok_build/search_replace/mod.rs:120-127)."
  },
  "read.partial_ledger": {
    "score": 0,
    "evidence": "Searched for tracking of partial views / refusal of destructive overwrite. Read windows are not recorded anywhere (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:584-593), and search_replace's empty-old_string overwrite guard is off by default (empty_old_string_does_not_override=false at crates/codegen/xai-grok-tools/src/implementations/grok_build/search_replace/mod.rs:106-135)."
  },
  "read.did_you_mean": {
    "score": 0.5,
    "evidence": "Close-name suggestions exist: PathNotFoundHint renders 'Did you mean ...?' / 'Similar entries in parent directory: ...' plus a CWD note (crates/codegen/xai-grok-tools/src/util/path_suggestions.rs:32-51, 105-126), wired into read_file at crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:406-413. But the gate is off by default: path_not_found_hints=false at crates/codegen/xai-grok-shell/src/agent/config.rs:1838 (only overridable by remote settings at crates/codegen/xai-grok-shell/src/agent/config.rs:2356-2357)."
  },
  "read.unicode_retry": {
    "score": 1,
    "evidence": "A missing path is retried after Unicode normalization (e.g. U+202F -> ASCII space) before failing: crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:354-362 calls try_resolve_unicode_filename on NotFound; implementation at crates/codegen/xai-grok-tools/src/util/fs.rs:110-195 resolves a unique normalized match and returns a note."
  },
  "read.confusables": {
    "score": 0,
    "evidence": "Searched for zero-width/bidi disclosure in read content. The confusable module covers only eight typographic characters (smart quotes, dashes, ellipsis, NBSP) and never zero-width or bidi controls: crates/codegen/xai-grok-tools/src/util/unicode_confusables.rs:30-42. Zero-width/bidi stripping exists only in shell UI text sanitation (crates/codegen/xai-grok-shell/src/util/text_sanitize.rs:28-34), not read_file output."
  },
  "read.image_vision": {
    "score": 1,
    "evidence": "Images are magic-sniffed and returned as ImageContent (crates/codegen/xai-grok-tools/src/implementations/read_file/image.rs:71-105; crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:434-441), then attached to the model turn as a ContentPart::Image data URL with a 'Read image file: <path>' note (crates/codegen/xai-grok-shell/src/session/acp_session_impl/tool_calls.rs:2798-2822)."
  },
  "read.coord_scale": {
    "score": 0,
    "evidence": "Searched for a downscale/scale-factor disclosure. Images are downscaled for the payload budget (crates/codegen/xai-grok-tools/src/implementations/read_file/image.rs:136-143; crates/codegen/xai-grok-tools/src/util/image_compress.rs:61-130) but neither the tool output nor the session-layer note reports original vs rendered dimensions or a scale factor; the attachment note is only 'Read image file: <path>' (crates/codegen/xai-grok-shell/src/session/acp_session_impl/tool_calls.rs:2817-2822)."
  },
  "read.magic_bytes": {
    "score": 1,
    "evidence": "Media type comes from bytes: bytes_to_metadata uses the `infer` crate on raw bytes (crates/codegen/xai-grok-tools/src/implementations/read_file/metadata.rs:14-41), images are detected from that metadata before extension handling (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:434-442), and PDF detection tries infer metadata then %PDF- magic before extension (crates/codegen/xai-grok-tools/src/implementations/read_file/pdf.rs:348-353). A .png containing text fails infer and is then rejected as a binary extension (crates/codegen/xai-grok-tools/src/util/binary.rs:5-10,19-22)."
  },
  "read.notebooks": {
    "score": 0,
    "evidence": "Searched for .ipynb handling. The only occurrence in the whole repo is the tool description claiming notebooks are supported (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:104-111); there is no notebook parser, cell renderer, or output cap. The file falls through to the plain UTF-8 reader (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:467-480), so it renders as raw JSON with no tagged cells."
  },
  "read.docx": {
    "score": 0,
    "evidence": "Searched for a docx parser. The read pipeline has no docx branch (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:443-480 only special-cases PDF/PPTX/images), and docx is in the binary-extension denylist, so it is refused as binary at crates/codegen/xai-grok-tools/src/util/binary.rs:5-10,19-22."
  },
  "read.pptx": {
    "score": 1,
    "evidence": "PPTX renders as text with slide headers and speaker notes: dispatch at crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:464-466; extraction at crates/codegen/xai-grok-tools/src/implementations/read_file/pptx.rs:30-80 emits '--- Slide N ---' and a 'Speaker Notes:' section (crates/codegen/xai-grok-tools/src/implementations/read_file/pptx.rs:71-76), with numeric slide ordering and a 64MB per-entry cap (crates/codegen/xai-grok-tools/src/implementations/read_file/pptx.rs:22-24,52-66)."
  },
  "read.xlsx": {
    "score": 0,
    "evidence": "Searched for spreadsheet parsing. No xlsx handler exists in the read pipeline (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:443-480), and xlsx is refused as a binary extension at crates/codegen/xai-grok-tools/src/util/binary.rs:5-10. The only xlsx mention is a vendor-skill denylist entry (crates/codegen/xai-grok-tools/src/implementations/skills/discovery.rs:53), not a converter."
  },
  "read.odf": {
    "score": 0,
    "evidence": "Searched for OpenDocument support. No ODF branch exists in the read pipeline (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:443-480), and odp/ods/odt are all in the binary-extension denylist at crates/codegen/xai-grok-tools/src/util/binary.rs:5-10."
  },
  "read.rtf_epub": {
    "score": 0,
    "evidence": "Searched for RTF/EPUB parsing. Neither format has a handler in the read pipeline (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:443-480); EPUB is a zip container that reaches the binary sniff (crates/codegen/xai-grok-tools/src/util/binary.rs:19-43) and is rejected, and RTF markup is returned raw with no conversion."
  },
  "read.pdf_text": {
    "score": 0.5,
    "evidence": "Text extraction exists but is not the default: handle_pdf maps format None/'image' to page rendering and only format='text' to extract_pdf_text (crates/codegen/xai-grok-tools/src/implementations/read_file/pdf.rs:79-112), while the tool's format description documents 'image' as the default (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:145-149). Default reads attach rendered page images rather than inline text."
  },
  "read.scanned_pdf": {
    "score": 0,
    "evidence": "Searched 'scanned|ocr|text layer' across the tools and shell crates; no detection or recovery command exists. PDF text extraction silently appends nothing for a page with no text (crates/codegen/xai-grok-tools/src/implementations/read_file/pdf.rs:274-286), and the only recovery hint for large PDFs is the page-range error at crates/codegen/xai-grok-tools/src/implementations/read_file/pdf.rs:202-208."
  },
  "read.docs_windowed": {
    "score": 0,
    "evidence": "Documents bypass the line window: read_file returns immediately for PDFs and PPTX before offset/limit extraction (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:448-466), and raw_text_to_file_content line-numbers the entire extracted document with no window (crates/codegen/xai-grok-tools/src/implementations/read_file/pdf.rs:247-267). PPTX likewise returns all slides (crates/codegen/xai-grok-tools/src/implementations/read_file/pptx.rs:30-80)."
  },
  "read.docs_bulk": {
    "score": 0,
    "evidence": "The read input is a single target_file string with no array/multi-path form (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:117-150), and the PDF/PPTX branches consume only that one file (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:448-466). Documents cannot participate in a multi-file read."
  },
  "read.converter_on_demand": {
    "score": 1,
    "evidence": "No heavyweight converter is installed or required: PDF and PPTX extraction are compiled in via pdf_oxide, zip and quick-xml (crates/codegen/xai-grok-tools/Cargo.toml:33-43; crates/codegen/xai-grok-tools/src/implementations/read_file/pdf.rs:178-191 uses pdf_oxide::PdfDocument; crates/codegen/xai-grok-tools/src/implementations/read_file/pptx.rs:30-32 uses ZipArchive+quick-xml). No pandoc/libreoffice/poppler subprocess or first-use download exists in the read path."
  },
  "read.many_files": {
    "score": 0,
    "evidence": "ReadFileInput has a single required path and optional window fields, with no list/array of files (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:112-150). The tool resolves and reads exactly one path per call (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:347-362, 383-407)."
  },
  "read.globs": {
    "score": 0,
    "evidence": "The read tool has no glob parameter and does not expand patterns: input is a literal `target_file` (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:117-139), and the path is canonicalized/read directly (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:352-362, 381). Glob expansion exists only in list_dir/grep, not read."
  },
  "read.per_file_range": {
    "score": 0,
    "evidence": "The only offset/limit pair applies to the single path in ReadFileInput (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:117-150); there is no per-entry structure because there is no multi-file input."
  },
  "read.exclusions_gitignore": {
    "score": 0.5,
    "evidence": "Gitignore is honored for the single read when enabled: RespectGitignore gate at crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:367-380. But it is off by default (respect_gitignore=false at crates/codegen/xai-grok-shell/src/agent/config.rs:1835), and there are no exclusion/include patterns in the read input (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:117-150)."
  },
  "read.aggregate_cap": {
    "score": 0,
    "evidence": "Searched for a cross-file budget. There is no bulk read, hence no aggregate cap: the tool reads one path and enforces only that file's line window and 25k-token ceiling (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:495-562)."
  },
  "read.aliased_input": {
    "score": 0,
    "evidence": "Input leniency is numeric/bool only: offset uses deserialize_lenient_i64 and rejects nothing but bad numbers (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:123-133; crates/codegen/xai-grok-tools/src/types/schema.rs:95-150). There is no alias repair for common key spellings such as path/file_path/target_path on ReadFileInput (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:117-150)."
  },
  "read.negative_offset": {
    "score": 1,
    "evidence": "Negative offsets read the tail: resolve_read_start_line computes total_fields + offset + 1 and clamps at 1 (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:156-176), with offset=0 treated as line 1 (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:163-169) and the resolved start applied to extraction (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:251)."
  },
  "read.device_blocklist": {
    "score": 0,
    "evidence": "Searched for a device-path denylist before I/O. The read tool canonicalizes and calls fs.read_file with no /dev or block-device check (crates/codegen/xai-grok-tools/src/implementations/grok_build/read_file/mod.rs:352-381; crates/codegen/xai-grok-tools/src/computer/local/file_system.rs:133-145). The sandbox's DEVICE_FILES/DEVICE_DIRS lists are write-allow lists for sandboxing (crates/codegen/xai-grok-sandbox/src/paths.rs:14-38), and the sandbox is off by default (crates/codegen/xai-grok-shell/src/agent/config.rs:1189-1200)."
  }
}