harness-read 0.1.1

Read tool for AI agent harnesses — filesystem read with pagination, binary sniff, directory listing, attachment shape, NOT_FOUND fuzzy siblings
Documentation
use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ReadParams {
    pub path: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub offset: Option<usize>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub limit: Option<usize>,
}

#[derive(Debug, Clone, thiserror::Error)]
pub enum ReadParseError {
    #[error("{0}")]
    Message(String),
}

pub fn safe_parse_read_params(input: &Value) -> Result<ReadParams, ReadParseError> {
    let parsed: ReadParams = serde_json::from_value(input.clone())
        .map_err(|e| ReadParseError::Message(e.to_string()))?;
    if parsed.path.is_empty() {
        return Err(ReadParseError::Message("path must not be empty".to_string()));
    }
    if let Some(o) = parsed.offset {
        if o < 1 {
            return Err(ReadParseError::Message("offset must be >= 1".to_string()));
        }
    }
    if let Some(l) = parsed.limit {
        if l < 1 {
            return Err(ReadParseError::Message("limit must be >= 1".to_string()));
        }
    }
    Ok(parsed)
}

pub const READ_TOOL_NAME: &str = "read";
pub const READ_TOOL_DESCRIPTION: &str = "Read a file or directory from the local filesystem.\n\nUsage:\n- The path parameter should be an absolute path. If relative, it resolves against the session working directory.\n- By default, returns up to 2000 lines from the start of the file.\n- The offset parameter is the 1-indexed line number to start from.\n- For later sections, call this tool again with a larger offset.\n- Use the grep tool for content search in large files; glob to locate files by pattern.\n- Contents are returned with each line prefixed by its line number as \"<line>: <content>\".\n- Any line longer than 2000 characters is truncated.\n- Call this tool in parallel when reading multiple files.\n- Avoid tiny repeated slices (under 30 lines). Read a larger window instead.\n- Images and PDFs are returned as file attachments.\n- Binary files are refused; use specialized tools.";