From 61561c696cdf403bcd715f89cff56573f43e234b Mon Sep 17 00:00:00 2001 From: IronAdamant <18153828+IronAdamant@users.noreply.github.com> Date: Thu, 5 Nov 2026 17:26:37 +1100 Subject: [PATCH 1/5] MCP tool groups, chosen in AGENTS.md or by env switches. Implements the suite's tool-group convention. The 31 MCP tools are in six groups: core (always on: bootstrap, lookups, dependencies, file wikis, update_maps), notes (record_change and the journal), health, map (resolution and barrel diagnostics), cycles, status (repeats of bootstrap). - Agents choose per project: the first fenced `agent-tools` block in AGENTS.md at the server's root may hold `wikifier: tools ` and `wikifier: disable `. WIKIFIER_TOOLS / WIKIFIER_DISABLE override those lines key by key. - Hidden tools leave tools/list; calling one returns isError naming the switch or block line to change. - An env mistake (unknown name, core in DISABLE) prints one line and exits 2. A block mistake is a warning in the initialize instructions and list_core_tools, and that line is ignored. - The server stats AGENTS.md before every request and sends notifications/tools/list_changed before the response when the exposed list changed. With a block or a switch, initialize advertises tools.listChanged and ends with the groups line. - With neither, initialize and tools/list are byte-identical to the 5.1.0 release (tests/fixtures/mcp_default_5.1.0.jsonl). The CLI ignores all of it. tools/list: 22.7 KB all on; 18.2 KB without notes, 17.0 without health, 20.8 without map, 21.9 without cycles, 19.4 without status; 16.8 KB (22 tools) for `disable map, cycles, status`; 6.6 KB for `tools core`. tests/tool_groups.rs runs the real server: default unchanged, filters by group and tool name, refusal text, exit 2, core protected, block precedence and warnings, the live list_changed notice, and the fence parser. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CMYkogM3QWVjMLzWKGyjuJ --- .gitattributes | 1 + src/lib.rs | 1 + src/lib.rs.wiki.md | 2 +- src/mcp.rs | 310 ++++++++++++--- src/mcp.rs.wiki.md | 2 +- src/mcp_groups.rs | 426 +++++++++++++++++++++ src/mcp_groups.rs.wiki.md | 5 + tests/dogfood.rs | 2 + tests/fixtures/mcp_default_5.1.0.jsonl | 2 + tests/tool_groups.rs | 508 +++++++++++++++++++++++++ 10 files changed, 1203 insertions(+), 56 deletions(-) create mode 100644 src/mcp_groups.rs create mode 100644 src/mcp_groups.rs.wiki.md create mode 100644 tests/fixtures/mcp_default_5.1.0.jsonl create mode 100644 tests/tool_groups.rs diff --git a/.gitattributes b/.gitattributes index c825a3f..6e67fd5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,4 @@ *.sh text eol=lf *.bat text eol=crlf *.ps1 text eol=crlf +*.jsonl text eol=lf diff --git a/src/lib.rs b/src/lib.rs index b7b04ed..01c4c7e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ mod legacy_cache; mod low_conf; pub mod maps_out; pub mod mcp; +pub mod mcp_groups; pub mod parse; mod pending_line; mod proc; diff --git a/src/lib.rs.wiki.md b/src/lib.rs.wiki.md index 3793643..136dfff 100644 --- a/src/lib.rs.wiki.md +++ b/src/lib.rs.wiki.md @@ -2,4 +2,4 @@ **Role:** Crate root for the std-only Wikifier core. -Public modules are `api`, `artifacts`, `cache`, `jsonutil`, `maps_out`, `mcp`, `parse`, `scope`, `sha256`, and `timeutil`. `legacy_cache`, `project_lock`, `cache_commit`, and `proc` stay private. Re-exported names: `cache_status`, `check_changes`, `health`, `list_paths`, `load_dependencies`, `load_dependents`, `mapped_edges`, `mark_green`, `prepare_edit`, `read_health`, `read_journal`, `record_change`, `session_bootstrap`, `suggest_next_actions`, `update_maps`, `VERSION`, and `Json`. +Public modules are `api`, `artifacts`, `cache`, `jsonutil`, `maps_out`, `mcp`, `mcp_groups` (MCP tool groups and their switches), `parse`, `scope`, `sha256`, `symbols`, `text_out`, and `timeutil`. `legacy_cache`, `project_lock`, `cache_commit`, `cycle_report`, `daemon_svc`, `low_conf`, `pending_line`, `wiki_files`, and `proc` stay private. Re-exported names: `cache_status`, `check_changes`, `health`, `list_paths`, `load_dependencies`, `load_dependents`, `mapped_edges`, `mark_green`, `prepare_edit`, `read_health`, `read_journal`, `record_change`, `session_bootstrap`, `suggest_next_actions`, `update_maps`, `VERSION`, and `Json`. diff --git a/src/mcp.rs b/src/mcp.rs index 6c31903..d53fd07 100644 --- a/src/mcp.rs +++ b/src/mcp.rs @@ -8,6 +8,138 @@ use std::time::Duration; use crate::api::{self, MCP_TOOLS}; use crate::jsonutil::{self, Json}; +use crate::mcp_groups::{AgentTools, Selection, DISABLE_VAR, TOOLS_VAR}; + +/// Tool-group state for this server: the selection, the block's warnings, and the AGENTS.md +/// stamp that [`refresh`] compares before every request. +#[derive(Clone)] +pub struct GroupState { + pub selection: Selection, + pub warnings: Vec, + /// A switch is set or AGENTS.md has an `agent-tools` block. Only then does `initialize` + /// advertise `listChanged` and carry the groups line; otherwise every reply is as before. + pub shaped: bool, + agents: Option, + stamp: Option<(std::time::SystemTime, u64)>, + env_tools: Option, + env_disable: Option, +} + +static STATE: std::sync::Mutex> = std::sync::Mutex::new(None); + +/// The notification sent before a response when an AGENTS.md edit changed the tool list. +pub const LIST_CHANGED: &str = r#"{"jsonrpc":"2.0","method":"notifications/tools/list_changed"}"#; + +/// The tools this server exposes. Every tool until [`configure`] runs. +pub fn active() -> Selection { + groups_state().selection +} + +pub fn groups_state() -> GroupState { + STATE + .lock() + .ok() + .and_then(|guard| guard.clone()) + .unwrap_or_else(|| GroupState { + selection: Selection::all(), + warnings: Vec::new(), + shaped: false, + agents: None, + stamp: None, + env_tools: None, + env_disable: None, + }) +} + +impl GroupState { + fn load( + agents: Option, + env_tools: Option, + env_disable: Option, + ) -> Result { + let stamp = agents.as_deref().and_then(stamp_of); + let block = agents + .as_deref() + .and_then(|path| std::fs::read_to_string(path).ok()) + .map(|text| AgentTools::parse(&text)) + .unwrap_or_default(); + let (selection, warnings) = + Selection::resolve(env_tools.as_deref(), env_disable.as_deref(), &block)?; + Ok(GroupState { + selection, + warnings, + shaped: block.found || env_tools.is_some() || env_disable.is_some(), + agents, + stamp, + env_tools, + env_disable, + }) + } + + /// Block warnings first, then the groups line. + pub fn instructions(&self) -> String { + let mut lines = self.warnings.clone(); + lines.push(self.selection.summary()); + lines.join("\n") + } +} + +fn stamp_of(path: &std::path::Path) -> Option<(std::time::SystemTime, u64)> { + let meta = std::fs::metadata(path).ok()?; + Some((meta.modified().ok()?, meta.len())) +} + +/// Read `WIKIFIER_TOOLS`, `WIKIFIER_DISABLE`, and the `agent-tools` block of AGENTS.md in +/// the server's project root (`WIKIFIER_PROJECT_ROOT`, else the working directory). `Err` +/// is an environment mistake; the server prints it and exits 2. +pub fn configure() -> Result<(), String> { + let env = |key: &str| std::env::var(key).ok().filter(|v| !v.trim().is_empty()); + let root = env("WIKIFIER_PROJECT_ROOT") + .map(PathBuf::from) + .or_else(|| std::env::current_dir().ok()); + let state = GroupState::load( + root.map(|root| root.join("AGENTS.md")), + env(TOOLS_VAR), + env(DISABLE_VAR), + )?; + if let Ok(mut guard) = STATE.lock() { + *guard = Some(state); + } + Ok(()) +} + +/// Stat AGENTS.md (mtime and size) and reload it when it changed. True when the exposed +/// tool list changed, so the caller sends [`LIST_CHANGED`] before its response. +pub fn refresh() -> bool { + let Ok(mut guard) = STATE.lock() else { + return false; + }; + let Some(state) = guard.as_mut() else { + return false; + }; + let Some(path) = state.agents.clone() else { + return false; + }; + let stamp = stamp_of(&path); + if stamp == state.stamp { + return false; + } + match GroupState::load( + Some(path), + state.env_tools.clone(), + state.env_disable.clone(), + ) { + Ok(next) => { + let changed = next.selection.enabled() != state.selection.enabled(); + *state = next; + changed + } + Err(_) => { + state.stamp = stamp; + false + } + } +} fn extra_props(name: &str) -> Vec<(&'static str, Json)> { let boolean = |description: &str| { @@ -318,65 +450,19 @@ pub fn handle_message(msg: &Json) -> Option { let method = msg.get("method").and_then(|m| m.as_str()).unwrap_or(""); id.as_ref()?; let result = match method { - "initialize" => Json::obj(vec![ - ("protocolVersion", Json::String("2024-11-05".into())), - ( - "capabilities", - Json::obj(vec![ - ("tools", Json::obj(vec![])), - ("resources", Json::obj(vec![])), - ("prompts", Json::obj(vec![])), - ]), - ), - ( - "serverInfo", - Json::obj(vec![ - ("name", Json::String("wikifier".into())), - ("version", Json::String(api::VERSION.into())), - ]), - ), - ]), + "initialize" => initialize(), "tools/list" => Json::obj(vec![( "tools", - Json::Array(MCP_TOOLS.iter().map(|n| tool_schema(n)).collect()), - )]), - "resources/list" => Json::obj(vec![( - "resources", - Json::Array( - [ - "wikifier://library", - "wikifier://health", - "wikifier://pending", - "wikifier://journal", - ] - .into_iter() - .map(|u| { - Json::obj(vec![ - ("uri", Json::String(u.into())), - ("name", Json::String(u.into())), - ]) - }) - .collect(), - ), - )]), - "prompts/list" => Json::obj(vec![( - "prompts", Json::Array( - [ - "review_pending_changes", - "audit_project_health", - "plan_refactoring", - "find_architectural_smells", - "understand_codebase_structure", - "review_recent_changes", - "generate_project_health_report", - "onboard_to_module", - ] - .into_iter() - .map(|n| Json::obj(vec![("name", Json::String(n.into()))])) - .collect(), + MCP_TOOLS + .iter() + .filter(|n| active().allows(n)) + .map(|n| tool_schema(n)) + .collect(), ), )]), + "resources/list" => resources_list(), + "prompts/list" => prompts_list(), "resources/read" => resource_read(msg), "prompts/get" => prompt_get(msg), "tools/call" => call_tool(msg), @@ -393,6 +479,82 @@ pub fn handle_message(msg: &Json) -> Option { ])) } +fn initialize() -> Json { + let state = groups_state(); + // listChanged only when groups are in play, so a server with no switch and no block + // answers exactly as 5.1.0 did. + let tools = if state.shaped { + Json::obj(vec![("listChanged", Json::Bool(true))]) + } else { + Json::obj(vec![]) + }; + let mut value = Json::obj(vec![ + ("protocolVersion", Json::String("2024-11-05".into())), + ( + "capabilities", + Json::obj(vec![ + ("tools", tools), + ("resources", Json::obj(vec![])), + ("prompts", Json::obj(vec![])), + ]), + ), + ( + "serverInfo", + Json::obj(vec![ + ("name", Json::String("wikifier".into())), + ("version", Json::String(api::VERSION.into())), + ]), + ), + ]); + if state.shaped { + value.insert("instructions", Json::String(state.instructions())); + } + value +} + +fn resources_list() -> Json { + Json::obj(vec![( + "resources", + Json::Array( + [ + "wikifier://library", + "wikifier://health", + "wikifier://pending", + "wikifier://journal", + ] + .into_iter() + .map(|u| { + Json::obj(vec![ + ("uri", Json::String(u.into())), + ("name", Json::String(u.into())), + ]) + }) + .collect(), + ), + )]) +} + +fn prompts_list() -> Json { + Json::obj(vec![( + "prompts", + Json::Array( + [ + "review_pending_changes", + "audit_project_health", + "plan_refactoring", + "find_architectural_smells", + "understand_codebase_structure", + "review_recent_changes", + "generate_project_health_report", + "onboard_to_module", + ] + .into_iter() + .map(|n| Json::obj(vec![("name", Json::String(n.into()))])) + .collect(), + ), + )]) +} + fn call_tool(msg: &Json) -> Json { let params = msg.get("params"); let name = params @@ -401,6 +563,14 @@ fn call_tool(msg: &Json) -> Json { .unwrap_or("") .to_string(); let args = params.and_then(|p| p.get("arguments")).cloned(); + if !active().allows(&name) { + let refusal = Json::obj(vec![ + ("success", Json::Bool(false)), + ("error", Json::String(active().refusal(&name))), + ("error_type", Json::String("ToolDisabled".into())), + ]); + return tool_result(refusal, false, &name); + } if let Some(err) = missing_required(&name, args.as_ref()) { return tool_result(err, false, &name); } @@ -600,9 +770,31 @@ fn call_tool(msg: &Json) -> Json { ("may_still_complete", Json::Bool(true)), ]), }; + let value = if tool_name == "list_core_tools" && groups_state().shaped { + with_active_groups(value) + } else { + value + }; tool_result(value, textual, &tool_name) } +/// `list_core_tools` under `WIKIFIER_TOOLS` / `WIKIFIER_DISABLE`: only the tools this +/// server exposes, plus the one-line group summary. +fn with_active_groups(mut value: Json) -> Json { + for key in ["core", "tools"] { + if let Some(Json::Array(items)) = value.get(key) { + let kept: Vec = items + .iter() + .filter(|item| item.as_str().is_some_and(|name| active().allows(name))) + .cloned() + .collect(); + value.insert(key, Json::Array(kept)); + } + } + value.insert("groups", Json::String(groups_state().instructions())); + value +} + /// A required argument the client left out fails the call and names the accepted fields, /// so an agent that guessed `file_path` or `path` can retry at once. Without this the tool /// ran with an empty path and answered `success: true` with every field empty. @@ -806,6 +998,13 @@ fn prompt_text(name: &str) -> &'static str { } pub fn serve_stdio() -> Result<(), String> { + // A typo in WIKIFIER_TOOLS / WIKIFIER_DISABLE stops the server, so the MCP client + // shows it as failed instead of serving a silently different tool set. + // A block mistake in AGENTS.md only warns: an agent wrote it and reads the warning. + if let Err(message) = configure() { + eprintln!("{message}"); + std::process::exit(2); + } let stdin = std::io::stdin(); let mut reader = stdin.lock(); let mut stdout = std::io::stdout().lock(); @@ -823,6 +1022,9 @@ pub fn serve_stdio() -> Result<(), String> { Ok(v) => v, Err(_) => continue, }; + if refresh() { + writeln!(stdout, "{LIST_CHANGED}").map_err(|e| e.to_string())?; + } if let Some(resp) = handle_message(&msg) { writeln!(stdout, "{resp}").map_err(|e| e.to_string())?; stdout.flush().map_err(|e| e.to_string())?; diff --git a/src/mcp.rs.wiki.md b/src/mcp.rs.wiki.md index 0abd0ac..91eccba 100644 --- a/src/mcp.rs.wiki.md +++ b/src/mcp.rs.wiki.md @@ -2,6 +2,6 @@ **Role:** Stdio JSON-RPC MCP adapter over `src/api.rs`. -`tool_schema` describes one tool. `handle_message` answers one JSON-RPC request. `serve_stdio` reads messages from stdin. `tools/call` sets `isError` when the payload has `success: false`. `resources/read` serves the library, health, pending, and journal resources. `prompts/get` returns a short user message. Each call runs on a thread and stops waiting after `WIKIFIER_MCP_DEADLINE_S` seconds (default 60). A timeout payload has `timed_out` and `may_still_complete`. +`tool_schema` describes one tool. `handle_message` answers one JSON-RPC request. `serve_stdio` reads messages from stdin. `configure` reads `WIKIFIER_TOOLS` / `WIKIFIER_DISABLE` and the AGENTS.md `agent-tools` block into a `GroupState` (exit 2 on an env mistake). Before each message `refresh` stats AGENTS.md and reloads it; when the tool list changed, `serve_stdio` writes `LIST_CHANGED` before the response. `active` and `groups_state` read the current state. `tools/list` lists only the tools `active` allows, `initialize` adds an `instructions` line and `list_core_tools` a `groups` line when either switch is set, and a call to a hidden tool returns `ToolDisabled`. `tools/call` sets `isError` when the payload has `success: false`. `resources/read` serves the library, health, pending, and journal resources. `prompts/get` returns a short user message. Each call runs on a thread and stops waiting after `WIKIFIER_MCP_DEADLINE_S` seconds (default 60). A timeout payload has `timed_out` and `may_still_complete`. A `tools/call` that leaves out a required argument other than `project_root` (or sends it empty) gets `InvalidArguments` naming the missing field, the accepted fields, and the fields received. `project_root` falls back to `WIKIFIER_PROJECT_ROOT`, then the cwd. `update_maps` omits the edge list unless `edges: true`; `edges_persisted` still gives the count. `health` takes `limit` (adds `entries_total` when it cuts) and `summary`. `session_bootstrap` and `get_project_status` cap `files` at `MCP_BOOTSTRAP_FILES` (100) unless the call passes `limit` (`0` lists all). diff --git a/src/mcp_groups.rs b/src/mcp_groups.rs new file mode 100644 index 0000000..9533478 --- /dev/null +++ b/src/mcp_groups.rs @@ -0,0 +1,426 @@ +//! MCP tool groups, chosen per project by an agent (the `agent-tools` block in AGENTS.md) +//! or by the operator (`WIKIFIER_TOOLS` / `WIKIFIER_DISABLE`, which win per key). +//! The suite-wide convention: every tool is in one group, `core` is always on, an env +//! mistake stops the server, a block mistake is a warning, and with no switch and no +//! block nothing changes. + +use std::collections::BTreeSet; + +use crate::api::MCP_TOOLS; + +pub const TOOLS_VAR: &str = "WIKIFIER_TOOLS"; +pub const DISABLE_VAR: &str = "WIKIFIER_DISABLE"; + +/// Every MCP tool, by group. `core` is always on: the lookups plus `update_maps`, which the +/// daily loop needs. `map` holds the resolution and barrel diagnostics. +pub const GROUPS: &[(&str, &[&str])] = &[ + ( + "core", + &[ + "session_bootstrap", + "prepare_edit", + "get_dependencies", + "get_dependents", + "get_file_wiki", + "list_paths", + "suggest_next_actions", + "update_maps", + ], + ), + ( + "notes", + &[ + "record_change", + "record_changes", + "record_deletion", + "search_journal", + "why_file", + "journal", + ], + ), + ( + "health", + &[ + "check_changes", + "mark_green", + "verify_wikis", + "health", + "validate", + "list_healable_stubs", + "heal_stubs", + "seed_source_content_hashes", + ], + ), + ( + "map", + &[ + "get_resolution_diagnostics", + "get_barrel_reports", + "get_incremental_status", + ], + ), + ("cycles", &["get_cycles"]), + ( + "status", + &[ + "list_core_tools", + "get_project_status", + "get_current_project_root", + "issues", + "get_files_needing_attention", + ], + ), +]; + +/// The group a tool belongs to. +pub fn group_of(tool: &str) -> Option<&'static str> { + GROUPS + .iter() + .find(|(_, tools)| tools.contains(&tool)) + .map(|(group, _)| *group) +} + +/// Where one key of a selection came from: the operator's environment or the agent's +/// `agent-tools` block in AGENTS.md. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Source { + Env, + AgentsMd, +} + +/// Which tools the MCP surface exposes, and why the others are off. +#[derive(Clone, Debug)] +pub struct Selection { + enabled: BTreeSet<&'static str>, + tools: Option<(Vec, Source)>, + disable: Option<(Vec, Source)>, +} + +impl Selection { + /// Every tool on: no switch and no block. + pub fn all() -> Self { + Selection { + enabled: MCP_TOOLS.iter().copied().collect(), + tools: None, + disable: None, + } + } + + /// Read the two variables from the environment. A blank value counts as unset. + pub fn from_env() -> Result { + Self::parse( + env_value(TOOLS_VAR).as_deref(), + env_value(DISABLE_VAR).as_deref(), + ) + } + + /// `tools` is the allowlist (`None` = every tool), `disable` is applied after it. + /// Names are groups or tool names; case and whitespace are ignored, and a blank value + /// is unset. `core` stays on: naming it, or one of its tools, in `disable` is an error. + pub fn parse(tools: Option<&str>, disable: Option<&str>) -> Result { + Self::resolve(tools, disable, &AgentTools::default()).map(|(selection, _)| selection) + } + + /// The environment wins per key: `WIKIFIER_TOOLS` over the block's `tools` line and + /// `WIKIFIER_DISABLE` over its `disable` line. An environment error is returned (the + /// server exits 2). A block error is a warning: that line is ignored and the default + /// applies to its key. + pub fn resolve( + env_tools: Option<&str>, + env_disable: Option<&str>, + block: &AgentTools, + ) -> Result<(Self, Vec), String> { + let env_tools = env_tools.filter(|text| !text.trim().is_empty()); + let env_disable = env_disable.filter(|text| !text.trim().is_empty()); + let mut warnings = block.warnings.clone(); + let tools = match (env_tools, &block.tools) { + (Some(text), _) => Some(( + split_names(text, true).map_err(|name| env_unknown(TOOLS_VAR, &name))?, + Source::Env, + )), + (None, Some(text)) => match split_names(text, true) { + Ok(list) => Some((list, Source::AgentsMd)), + Err(name) => { + warnings.push(block_unknown(&name)); + None + } + }, + (None, None) => None, + }; + let disable = match (env_disable, &block.disable) { + (Some(text), _) => { + let list = + split_names(text, false).map_err(|name| env_unknown(DISABLE_VAR, &name))?; + if let Some(name) = core_named(&list) { + return Err(format!( + "{DISABLE_VAR}: \"{name}\" cannot be disabled, group \"core\" is always on; groups: {}", + group_names().join(", ") + )); + } + Some((list, Source::Env)) + } + (None, Some(text)) => match split_names(text, false) { + Ok(list) => match core_named(&list) { + Some(name) => { + warnings.push(format!( + "AGENTS.md agent-tools: \"{name}\" cannot be disabled for wikifier, group \"core\" is always on; groups: {}", + group_names().join(", ") + )); + None + } + None => Some((list, Source::AgentsMd)), + }, + Err(name) => { + warnings.push(block_unknown(&name)); + None + } + }, + (None, None) => None, + }; + let mut enabled: BTreeSet<&'static str> = match &tools { + Some((list, _)) if !list.iter().any(|name| name == "all") => MCP_TOOLS + .iter() + .copied() + .filter(|tool| matches(list, tool)) + .collect(), + _ => MCP_TOOLS.iter().copied().collect(), + }; + if let Some((list, _)) = &disable { + enabled.retain(|tool| !matches(list, tool)); + } + enabled.extend(core_tools()); + Ok(( + Selection { + enabled, + tools, + disable, + }, + warnings, + )) + } + + /// True when a switch or a block line shaped this selection. + pub fn is_filtered(&self) -> bool { + self.tools.is_some() || self.disable.is_some() + } + + pub fn allows(&self, tool: &str) -> bool { + self.enabled.contains(tool) || group_of(tool).is_none() + } + + /// The exposed tools, for noticing that a block edit changed the list. + pub fn enabled(&self) -> &BTreeSet<&'static str> { + &self.enabled + } + + /// The one-line error for calling a tool that is switched off. + pub fn refusal(&self, tool: &str) -> String { + let group = group_of(tool).unwrap_or(""); + if let Some((list, source)) = &self.disable { + if let Some(name) = list + .iter() + .find(|name| name.as_str() == group || name.as_str() == tool) + { + return match source { + Source::Env => format!( + "tool \"{tool}\" is disabled (group \"{group}\") by {DISABLE_VAR}; remove \"{name}\" from it to enable" + ), + Source::AgentsMd => format!( + "tool \"{tool}\" is disabled (group \"{group}\") by AGENTS.md agent-tools; remove \"{name}\" from the \"wikifier: disable\" line to enable" + ), + }; + } + } + match self.tools.as_ref().map(|(_, source)| *source) { + Some(Source::AgentsMd) => format!( + "tool \"{tool}\" is disabled (group \"{group}\") by AGENTS.md agent-tools; add \"{group}\" to the \"wikifier: tools\" line to enable" + ), + _ => format!( + "tool \"{tool}\" is disabled (group \"{group}\") by {TOOLS_VAR}; add \"{group}\" to it to enable" + ), + } + } + + /// Groups with at least one tool on, in table order. + pub fn active_groups(&self) -> Vec<&'static str> { + GROUPS + .iter() + .filter(|(_, tools)| tools.iter().any(|tool| self.enabled.contains(tool))) + .map(|(group, _)| *group) + .collect() + } + + /// The closing line of the `initialize` instructions and of `list_core_tools`. + pub fn summary(&self) -> String { + let on = self.active_groups(); + let off: Vec<&str> = group_names() + .into_iter() + .filter(|group| !on.contains(group)) + .collect(); + format!( + "Wikifier tool groups on: {}; off: {}. Change them with a \"wikifier: tools ...\" or \"wikifier: disable ...\" line in the agent-tools block of AGENTS.md ({TOOLS_VAR} / {DISABLE_VAR} override it).", + on.join(", "), + if off.is_empty() { + "none".to_string() + } else { + off.join(", ") + } + ) + } +} + +/// This tool's lines from the first fenced `agent-tools` block of an AGENTS.md. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct AgentTools { + /// An `agent-tools` block exists, whether or not it has a wikifier line. + pub found: bool, + pub tools: Option, + pub disable: Option, + pub warnings: Vec, +} + +impl AgentTools { + /// Read the first fenced block whose info string is `agent-tools`. Lines for other + /// tools are ignored; `#` starts a comment; lists take commas or spaces. + pub fn parse(text: &str) -> Self { + let mut out = AgentTools::default(); + let mut fence: Option<(char, usize, bool)> = None; + for line in text.lines() { + let trimmed = line.trim_start(); + let shallow = line.len() - trimmed.len() <= 3; + if let Some((mark, len, ours)) = fence { + if shallow && closes(trimmed, mark, len) { + if ours { + return out; + } + fence = None; + } else if ours { + out.read_line(trimmed); + } + continue; + } + if shallow { + if let Some((mark, len, info)) = opens(trimmed) { + let ours = info.split_whitespace().next() == Some("agent-tools"); + out.found |= ours; + fence = Some((mark, len, ours)); + } + } + } + out + } + + fn read_line(&mut self, line: &str) { + let line = line.split('#').next().unwrap_or("").trim(); + let Some((tool, rest)) = line.split_once(':') else { + return; + }; + if !tool.trim().eq_ignore_ascii_case("wikifier") { + return; + } + let rest = rest.trim(); + let (key, list) = rest.split_once(char::is_whitespace).unwrap_or((rest, "")); + let list = list + .split(|c: char| c == ',' || c.is_whitespace()) + .filter(|name| !name.is_empty()) + .collect::>() + .join(","); + let slot = match key.to_ascii_lowercase().as_str() { + "tools" => &mut self.tools, + "disable" => &mut self.disable, + _ => { + self.warnings.push(format!( + "AGENTS.md agent-tools: unknown key \"{key}\" for wikifier; write \"wikifier: tools \" or \"wikifier: disable \"" + )); + return; + } + }; + match slot { + Some(existing) if !list.is_empty() => { + existing.push(','); + existing.push_str(&list); + } + Some(_) => {} + None => *slot = Some(list), + } + } +} + +/// A fence opening: at least three backticks or tildes, then the info string. +fn opens(line: &str) -> Option<(char, usize, &str)> { + let mark = line.chars().next().filter(|c| *c == '`' || *c == '~')?; + let len = line.chars().take_while(|c| *c == mark).count(); + if len < 3 { + return None; + } + let info = line[len..].trim(); + if mark == '`' && info.contains('`') { + return None; + } + Some((mark, len, info)) +} + +fn closes(line: &str, mark: char, len: usize) -> bool { + let line = line.trim_end(); + line.chars().count() >= len && line.chars().all(|c| c == mark) +} + +fn env_value(key: &str) -> Option { + std::env::var(key).ok().filter(|v| !v.trim().is_empty()) +} + +fn env_unknown(var: &str, name: &str) -> String { + format!( + "{var}: unknown group \"{name}\"; groups: {}; tools: {}", + group_names().join(", "), + MCP_TOOLS.join(", ") + ) +} + +fn block_unknown(name: &str) -> String { + format!( + "AGENTS.md agent-tools: unknown group \"{name}\" for wikifier; groups: {}", + group_names().join(", ") + ) +} + +fn core_named(list: &[String]) -> Option<&String> { + list.iter() + .find(|name| name.as_str() == "core" || group_of(name) == Some("core")) +} + +fn group_names() -> Vec<&'static str> { + GROUPS.iter().map(|(group, _)| *group).collect() +} + +fn core_tools() -> impl Iterator { + GROUPS + .iter() + .filter(|(group, _)| *group == "core") + .flat_map(|(_, tools)| tools.iter().copied()) +} + +fn matches(list: &[String], tool: &str) -> bool { + let group = group_of(tool).unwrap_or(""); + list.iter().any(|name| name == tool || name == group) +} + +/// Split on commas, trim, and lowercase; `Err` carries the first name that is no group or +/// tool (`all` only where it is allowed). +fn split_names(text: &str, allow_all: bool) -> Result, String> { + let mut out = Vec::new(); + for raw in text.split(',') { + let name = raw.trim().to_ascii_lowercase(); + if name.is_empty() { + continue; + } + let known = (allow_all && name == "all") + || GROUPS.iter().any(|(group, _)| *group == name) + || MCP_TOOLS.contains(&name.as_str()); + if !known { + return Err(name); + } + out.push(name); + } + Ok(out) +} diff --git a/src/mcp_groups.rs.wiki.md b/src/mcp_groups.rs.wiki.md new file mode 100644 index 0000000..c06506f --- /dev/null +++ b/src/mcp_groups.rs.wiki.md @@ -0,0 +1,5 @@ +# src/mcp_groups.rs + +**Role:** MCP tool groups and the on/off switches from the suite's tool-group convention. + +`GROUPS` puts every MCP tool in one group: `core` (always on, including `update_maps`), `notes`, `health`, `map`, `cycles`, `status`. `group_of` names a tool's group. `TOOLS_VAR` is `WIKIFIER_TOOLS` (allowlist, `all` accepted) and `DISABLE_VAR` is `WIKIFIER_DISABLE` (applied after it). `Selection::parse` and `Selection::from_env` read them (case and spaces ignored, empty means unset) and refuse an unknown name, or `core` or a core tool in `WIKIFIER_DISABLE`, with the one-line message the server prints before exiting 2. `Selection::resolve` combines the environment with an `AgentTools` block, key by key (env wins), and turns block mistakes into warnings. `AgentTools::parse` reads the first fenced `agent-tools` block of an AGENTS.md (backtick or tilde fences, nested fences skipped) and keeps only `wikifier:` lines. `Source` says whether a key came from the environment or the block. `Selection::all` is the unfiltered default. `enabled` exposes the tool set for change detection. `allows`, `refusal`, `active_groups`, `summary`, and `is_filtered` drive `src/mcp.rs`. diff --git a/tests/dogfood.rs b/tests/dogfood.rs index a5bdc40..c9ab757 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -282,6 +282,7 @@ fn prepare_edit_on_this_repo_lists_api_dependents() { "src/lib.rs", "src/main.rs", "src/mcp.rs", + "src/mcp_groups.rs", "tests/agent_args.rs", "tests/cli_surface.rs", "tests/contract_gaps.rs", @@ -290,6 +291,7 @@ fn prepare_edit_on_this_repo_lists_api_dependents() { "tests/robustness.rs", "tests/skip_maps.rs", "tests/speed_paths.rs", + "tests/tool_groups.rs", ]; assert_eq!(dependents, expected, "prepare-edit src/api.rs dependents"); diff --git a/tests/fixtures/mcp_default_5.1.0.jsonl b/tests/fixtures/mcp_default_5.1.0.jsonl new file mode 100644 index 0000000..a6ff9ff --- /dev/null +++ b/tests/fixtures/mcp_default_5.1.0.jsonl @@ -0,0 +1,2 @@ +{"id":1,"jsonrpc":"2.0","result":{"capabilities":{"prompts":{},"resources":{},"tools":{}},"protocolVersion":"2024-11-05","serverInfo":{"name":"wikifier","version":"5.1.0"}}} +{"id":2,"jsonrpc":"2.0","result":{"tools":[{"description":"Compare mapped files and Green baselines and report content drift.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"check_changes"},{"description":"Record a semantic edit against one file and mark that file actionable.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"file":{"description":"Project-relative source path.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"reason":{"description":"Why the file changed, or why a forced mark-green is still accurate.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root","file","reason"],"type":"object"},"name":"record_change"},{"description":"Record that a mapped file was removed and should leave the health matrix.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"file":{"description":"Project-relative source path.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"reason":{"description":"Why the file changed, or why a forced mark-green is still accurate.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root","file","reason"],"type":"object"},"name":"record_deletion"},{"description":"Mark a file Green after its wiki names the file's public symbols.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"file":{"description":"Project-relative source path.","type":"string"},"force":{"description":"Override a failed wiki check. Requires a reason.","type":"boolean"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"reason":{"description":"Why the file changed, or why a forced mark-green is still accurate.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root","file"],"type":"object"},"name":"mark_green"},{"description":"Record git changes in one batch. Pass per-file reasons when you have them.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"reasons":{"description":"Map of path, glob, or dir/ to a reason. A string array of PATH=REASON lines also works.","type":"object"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"record_changes"},{"description":"Check every Green wiki against the public symbols currently in the source.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"limit":{"description":"Cap listed failures or stale rows.","type":"integer"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"verify_wikis"},{"description":"Look up health, wiki text, dependencies, and dependents before editing a file.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"file":{"description":"Project-relative source path.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root","file"],"type":"object"},"name":"prepare_edit"},{"description":"Return readiness, health, suggested actions, and the mapped file list for this root.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"limit":{"description":"Cap the files list. Default 100 over MCP; 0 lists every file. files_total gives the count. Orient with map_index and list_paths.","type":"integer"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"session_bootstrap"},{"description":"Return the next agent actions, highest priority first.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"limit":{"description":"Cap listed failures or stale rows.","type":"integer"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"suggest_next_actions"},{"description":"List the daily core tools and the full MCP tool catalogue.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"list_core_tools"},{"description":"List mapped files under a project-relative prefix.","inputSchema":{"properties":{"depth":{"description":"1 is the folder card. 0 lists every file under the prefix.","type":"integer"},"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"max_files":{"description":"Cap the returned file list.","type":"integer"},"prefix":{"description":"Project-relative directory prefix. Omit to list the whole map.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"recursive":{"description":"Same as depth 0.","type":"boolean"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"list_paths"},{"description":"Search journal entries by file path or reason text.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"query":{"description":"Substring matched against journal file paths and reasons.","type":"string"},"text":{"description":"Alias of query.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root","query"],"type":"object"},"name":"search_journal"},{"description":"Return the journal reasons recorded for one file.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"file":{"description":"Project-relative source path.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root","file"],"type":"object"},"name":"why_file"},{"description":"Return internal edges, external imports, and unresolved imports for one file.","inputSchema":{"properties":{"detail":{"description":"compact or full. full adds confidence reasons.","type":"string"},"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"file":{"description":"Project-relative source path.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"low_confidence_only":{"description":"Keep resolved edges below 0.65 that are not dynamic.","type":"boolean"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"},"unresolved_only":{"description":"Keep only imports that did not resolve to a project file.","type":"boolean"}},"required":["project_root","file"],"type":"object"},"name":"get_dependencies"},{"description":"Return the mapped files that import a given file.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"file":{"description":"Project-relative source path.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root","file"],"type":"object"},"name":"get_dependents"},{"description":"Return import cycles in the mapped graph.","inputSchema":{"properties":{"analysis":{"description":"Include severity and reverse-dependency ranking. Default true.","type":"boolean"},"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"max_items":{"description":"Cap the cycle list.","type":"integer"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"get_cycles"},{"description":"Return resolution and barrel diagnostics for the current map.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"get_resolution_diagnostics"},{"description":"Return the wiki markdown stored beside a source file.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"file":{"description":"Project-relative source path.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root","file"],"type":"object"},"name":"get_file_wiki"},{"description":"Return files whose health is Red or an actionable Yellow.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"get_files_needing_attention"},{"description":"Return the same readiness snapshot as session bootstrap.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"limit":{"description":"Cap the files list. Default 100 over MCP; 0 lists every file. files_total gives the count. Orient with map_index and list_paths.","type":"integer"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"get_project_status"},{"description":"Return the absolute project root this call is using.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"get_current_project_root"},{"description":"Return barrel and incremental-resolution status for the current map.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"get_barrel_reports"},{"description":"Return whether the map is incremental and which barrels are recorded.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"get_incremental_status"},{"description":"Parse the scoped tree and commit one cache generation for the whole run.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"edges":{"description":"Include the whole edge list. Off by default: it runs to hundreds of KB on a mid-size repo. Use get_dependencies for one file.","type":"boolean"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"full":{"description":"Rehash every file instead of skipping unchanged size and mtime.","type":"boolean"},"max_files":{"description":"Parse at most this many changed files. Re-run while files_remaining_dirty > 0.","type":"integer"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"update_maps"},{"description":"Return the health matrix entries and the green, yellow, and red counts.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"limit":{"description":"Return at most this many entries. entries_total gives the full count.","type":"integer"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"summary":{"description":"Return only the green, yellow, and red counts.","type":"boolean"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"health"},{"description":"Check health coverage and that the forward and reverse cache indexes agree.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"validate"},{"description":"List Initial-stub files whose wiki is long enough to heal.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"min_wiki_length":{"description":"Minimum wiki length. Default 350.","type":"integer"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"list_healable_stubs"},{"description":"Promote Initial stubs that already have a long enough wiki.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"min_wiki_length":{"description":"Minimum wiki length. Default 350.","type":"integer"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"heal_stubs"},{"description":"Seed health rows from the current map without rewriting wikis.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"seed_source_content_hashes"},{"description":"Return journal entries, optionally for one date.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"journal"},{"description":"Return the same prioritized actions as suggest_next_actions.","inputSchema":{"properties":{"directory":{"description":"Limit the result to this project-relative prefix.","type":"string"},"format":{"description":"text or json. json is the default. text fills the content string with prose.","type":"string"},"project_root":{"description":"Absolute project root. Pass it on every call.","type":"string"},"timeout_s":{"description":"Stop this call after this many seconds. Falls back to WIKIFIER_MCP_DEADLINE_S.","type":"integer"}},"required":["project_root"],"type":"object"},"name":"issues"}]}} diff --git a/tests/tool_groups.rs b/tests/tool_groups.rs new file mode 100644 index 0000000..585e197 --- /dev/null +++ b/tests/tool_groups.rs @@ -0,0 +1,508 @@ +//! WIKIFIER_TOOLS / WIKIFIER_DISABLE, per the suite's tool-group convention. Each case +//! runs the real `wikifier mcp` with its own environment. + +use std::collections::BTreeSet; +use std::io::Write; +use std::path::PathBuf; +use std::process::{Command, Output, Stdio}; + +use wikifier::api::MCP_TOOLS; +use wikifier::jsonutil::{self, Json}; +use wikifier::mcp_groups::{group_of, Selection, GROUPS}; + +fn bin() -> PathBuf { + PathBuf::from(env!("CARGO_BIN_EXE_wikifier")) +} + +/// An empty project directory, so this repository's own AGENTS.md is not read. +fn project(name: &str) -> PathBuf { + let n = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_nanos(); + let dir = std::env::temp_dir().join(format!("wk-groups-{name}-{n}-{}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + dir +} + +/// Send `lines` to `wikifier mcp` with `env` set (and both switches cleared otherwise). +fn mcp(env: &[(&str, &str)], lines: &[&str]) -> Output { + mcp_in(&project("env"), env, lines) +} + +fn server(dir: &std::path::Path, env: &[(&str, &str)]) -> Command { + let mut cmd = Command::new(bin()); + cmd.arg("mcp") + .current_dir(dir) + .env_remove("WIKIFIER_PROJECT_ROOT") + .env_remove("WIKIFIER_TOOLS") + .env_remove("WIKIFIER_DISABLE") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + for (key, value) in env { + cmd.env(key, value); + } + cmd +} + +/// Run `wikifier mcp` in `dir` (its project root) and send `lines`. +fn mcp_in(dir: &std::path::Path, env: &[(&str, &str)], lines: &[&str]) -> Output { + let mut cmd = server(dir, env); + let mut child = cmd.spawn().unwrap(); + { + let mut stdin = child.stdin.take().unwrap(); + for line in lines { + writeln!(stdin, "{line}").unwrap(); + } + } + child.wait_with_output().unwrap() +} + +const LIST: &str = r#"{"jsonrpc":"2.0","id":1,"method":"tools/list"}"#; +const INIT: &str = r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}"#; + +fn replies(out: &Output) -> Vec { + String::from_utf8_lossy(&out.stdout) + .lines() + .map(|line| jsonutil::parse(line).unwrap()) + .collect() +} + +fn listed(env: &[(&str, &str)]) -> Vec { + let out = mcp(env, &[LIST]); + assert!( + out.status.success(), + "{}", + String::from_utf8_lossy(&out.stderr) + ); + replies(&out)[0] + .get("result") + .and_then(|r| r.get("tools")) + .and_then(|t| t.as_array()) + .unwrap() + .iter() + .map(|tool| { + tool.get("name") + .and_then(|n| n.as_str()) + .unwrap() + .to_string() + }) + .collect() +} + +fn tools_in(groups: &[&str]) -> Vec { + MCP_TOOLS + .iter() + .filter(|tool| groups.contains(&group_of(tool).unwrap())) + .map(|tool| tool.to_string()) + .collect() +} + +#[test] +fn every_tool_is_in_exactly_one_group() { + let mut seen = BTreeSet::new(); + for (_, tools) in GROUPS { + for tool in *tools { + assert!(MCP_TOOLS.contains(tool), "{tool} is not an MCP tool"); + assert!(seen.insert(*tool), "{tool} is in two groups"); + } + } + assert_eq!(seen.len(), MCP_TOOLS.len()); +} + +#[test] +fn the_default_listing_is_unchanged() { + let out = mcp(&[], &[INIT, LIST]); + let lines: Vec = String::from_utf8_lossy(&out.stdout) + .lines() + .map(|l| l.to_string()) + .collect(); + let expected = Json::obj(vec![ + ("jsonrpc", Json::String("2.0".into())), + ("id", Json::Int(1)), + ( + "result", + Json::obj(vec![( + "tools", + Json::Array( + MCP_TOOLS + .iter() + .map(|n| wikifier::mcp::tool_schema(n)) + .collect(), + ), + )]), + ), + ]); + assert_eq!(lines[1], expected.to_string()); + assert!(!lines[0].contains("instructions"), "{}", lines[0]); + // An empty variable is the same as an unset one. + assert_eq!( + listed(&[("WIKIFIER_TOOLS", " "), ("WIKIFIER_DISABLE", "")]).len(), + MCP_TOOLS.len() + ); +} + +#[test] +fn tools_and_disable_filter_by_group_and_by_tool_name() { + assert_eq!( + listed(&[("WIKIFIER_TOOLS", " Core , NOTES ")]), + tools_in(&["core", "notes"]) + ); + let mut core_and_cycles = tools_in(&["core"]); + core_and_cycles.push("get_cycles".into()); + let core_and_cycles: BTreeSet = core_and_cycles.into_iter().collect(); + let got: BTreeSet = listed(&[("WIKIFIER_TOOLS", "get_cycles")]) + .into_iter() + .collect(); + assert_eq!(got, core_and_cycles); + assert_eq!( + listed(&[("WIKIFIER_DISABLE", "map,cycles,status")]), + tools_in(&["core", "notes", "health"]) + ); + let without = listed(&[("WIKIFIER_DISABLE", "journal")]); + assert_eq!(without.len(), MCP_TOOLS.len() - 1); + assert!(!without.contains(&"journal".to_string())); + // _DISABLE applies after _TOOLS. + let both = listed(&[("WIKIFIER_TOOLS", "all"), ("WIKIFIER_DISABLE", "notes")]); + assert_eq!( + both, + tools_in(&["core", "health", "map", "cycles", "status"]) + ); +} + +#[test] +fn a_disabled_tool_answers_with_the_switch_to_change() { + let call = |name: &str| { + format!( + r#"{{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{{"name":"{name}","arguments":{{}}}}}}"# + ) + }; + let error_of = |env: &[(&str, &str)], name: &str| { + let reply = &replies(&mcp(env, &[&call(name)]))[0]; + let result = reply.get("result").unwrap(); + assert_eq!(result.get("isError"), Some(&Json::Bool(true)), "{reply}"); + result + .get("structuredContent") + .and_then(|v| v.get("error")) + .and_then(|v| v.as_str()) + .unwrap() + .to_string() + }; + assert_eq!( + error_of(&[("WIKIFIER_DISABLE", "notes")], "record_change"), + r#"tool "record_change" is disabled (group "notes") by WIKIFIER_DISABLE; remove "notes" from it to enable"# + ); + assert_eq!( + error_of(&[("WIKIFIER_TOOLS", "core")], "get_cycles"), + r#"tool "get_cycles" is disabled (group "cycles") by WIKIFIER_TOOLS; add "cycles" to it to enable"# + ); +} + +#[test] +fn an_unknown_name_stops_the_server_with_exit_code_2() { + let out = mcp(&[("WIKIFIER_DISABLE", "lokcs")], &[LIST]); + assert_eq!(out.status.code(), Some(2)); + assert!(out.stdout.is_empty()); + let stderr = String::from_utf8_lossy(&out.stderr); + assert_eq!(stderr.lines().count(), 1, "{stderr}"); + assert!( + stderr.starts_with( + r#"WIKIFIER_DISABLE: unknown group "lokcs"; groups: core, notes, health, map, cycles, status; tools: check_changes,"# + ), + "{stderr}" + ); + let out = mcp(&[("WIKIFIER_TOOLS", "core,mpa")], &[LIST]); + assert_eq!(out.status.code(), Some(2)); + assert!( + String::from_utf8_lossy(&out.stderr).starts_with(r#"WIKIFIER_TOOLS: unknown group "mpa""#) + ); + // `all` is only an allowlist word. + assert_eq!( + mcp(&[("WIKIFIER_DISABLE", "all")], &[LIST]).status.code(), + Some(2) + ); +} + +#[test] +fn core_cannot_be_disabled() { + for name in ["core", "Session_Bootstrap", "notes, update_maps"] { + let out = mcp(&[("WIKIFIER_DISABLE", name)], &[LIST]); + assert_eq!(out.status.code(), Some(2), "{name}"); + assert!(out.stdout.is_empty()); + let stderr = String::from_utf8_lossy(&out.stderr); + assert_eq!(stderr.lines().count(), 1, "{stderr}"); + assert!( + stderr.starts_with("WIKIFIER_DISABLE: \"") + && stderr.contains("\" cannot be disabled, group \"core\" is always on; groups: core, notes, health, map, cycles, status"), + "{stderr}" + ); + } + // An allowlist without core still keeps core. + assert_eq!(listed(&[("WIKIFIER_TOOLS", "cycles")]), { + let mut tools = tools_in(&["core", "cycles"]); + tools.sort_by_key(|t| MCP_TOOLS.iter().position(|m| m == t)); + tools + }); +} + +#[test] +fn default_initialize_and_tools_list_match_the_last_release() { + // The same two requests the fixture was recorded with, from the 5.1.0 release binary. + let list = r#"{"jsonrpc":"2.0","id":2,"method":"tools/list"}"#; + let out = mcp(&[], &[INIT, list]); + let golden = std::fs::read_to_string( + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/mcp_default_5.1.0.jsonl"), + ) + .unwrap() + .replace("\r\n", "\n") + .replace( + "\"version\":\"5.1.0\"", + &format!("\"version\":\"{}\"", env!("CARGO_PKG_VERSION")), + ); + assert_eq!(String::from_utf8_lossy(&out.stdout), golden); +} + +#[test] +fn initialize_and_list_core_tools_name_the_active_groups() { + let call = r#"{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_core_tools","arguments":{"project_root":"."}}}"#; + let out = mcp(&[("WIKIFIER_DISABLE", "map,cycles")], &[INIT, call]); + let got = replies(&out); + let line = "Wikifier tool groups on: core, notes, health, status; off: map, cycles. Change them with a \"wikifier: tools ...\" or \"wikifier: disable ...\" line in the agent-tools block of AGENTS.md (WIKIFIER_TOOLS / WIKIFIER_DISABLE override it)."; + assert_eq!( + got[0] + .get("result") + .and_then(|r| r.get("instructions")) + .and_then(|v| v.as_str()), + Some(line) + ); + let listed = got[1] + .get("result") + .and_then(|r| r.get("structuredContent")) + .unwrap(); + assert_eq!(listed.get("groups").and_then(|v| v.as_str()), Some(line)); + let tools = listed.get("tools").and_then(|v| v.as_array()).unwrap(); + assert_eq!(tools.len(), MCP_TOOLS.len() - 4); + assert!(!tools.iter().any(|t| t.as_str() == Some("get_cycles"))); +} + +#[test] +fn the_cli_ignores_the_switches() { + let out = Command::new(bin()) + .arg("list-core-tools") + .env("WIKIFIER_TOOLS", "core") + .output() + .unwrap(); + assert!(out.status.success()); + let text = String::from_utf8_lossy(&out.stdout); + assert!( + text.contains("get_cycles") && !text.contains("\"groups\""), + "{text}" + ); + // Selection itself: the parse used by the server. + assert!(Selection::parse(None, None).unwrap().allows("get_cycles")); + assert!(!Selection::parse(Some("core"), None) + .unwrap() + .allows("get_cycles")); +} + +fn write_agents(dir: &std::path::Path, block: &str) { + let text = format!( + "# Agents\n\nNotes for agents.\n\n```agent-tools\n{block}\n```\n\n```agent-tools\nwikifier: disable notes\n```\n" + ); + std::fs::write(dir.join("AGENTS.md"), text).unwrap(); +} + +fn names_of(reply: &Json) -> Vec { + reply + .get("result") + .and_then(|r| r.get("tools")) + .and_then(|t| t.as_array()) + .unwrap() + .iter() + .map(|tool| { + tool.get("name") + .and_then(|n| n.as_str()) + .unwrap() + .to_string() + }) + .collect() +} + +fn instructions_of(reply: &Json) -> String { + reply + .get("result") + .and_then(|r| r.get("instructions")) + .and_then(|v| v.as_str()) + .unwrap_or("") + .to_string() +} + +#[test] +fn the_agents_md_block_chooses_the_groups() { + let dir = project("block"); + // Only the first agent-tools block counts; other tools' lines and comments are skipped. + write_agents( + &dir, + "# one agent works here\ntrammel: disable locks, notes\nwikifier: disable map cycles\nchisel: tools core", + ); + let got = replies(&mcp_in(&dir, &[], &[INIT, LIST])); + let init = got[0].get("result").unwrap(); + assert_eq!( + init.get("capabilities") + .and_then(|c| c.get("tools")) + .and_then(|t| t.get("listChanged")), + Some(&Json::Bool(true)) + ); + assert!(instructions_of(&got[0]) + .starts_with("Wikifier tool groups on: core, notes, health, status; off: map, cycles.")); + assert_eq!( + names_of(&got[1]), + tools_in(&["core", "notes", "health", "status"]) + ); + + let call = r#"{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_cycles","arguments":{}}}"#; + let refused = &replies(&mcp_in(&dir, &[], &[call]))[0]; + assert_eq!( + refused + .get("result") + .and_then(|r| r.get("structuredContent")) + .and_then(|v| v.get("error")) + .and_then(|v| v.as_str()), + Some( + r#"tool "get_cycles" is disabled (group "cycles") by AGENTS.md agent-tools; remove "cycles" from the "wikifier: disable" line to enable"# + ) + ); +} + +#[test] +fn the_environment_wins_per_key() { + let dir = project("precedence"); + write_agents( + &dir, + "wikifier: tools core, notes, cycles\nwikifier: disable cycles", + ); + // WIKIFIER_DISABLE replaces the block's disable line; its tools line still applies. + let got = replies(&mcp_in(&dir, &[("WIKIFIER_DISABLE", "notes")], &[LIST])); + assert_eq!(names_of(&got[0]), tools_in(&["core", "cycles"])); + // WIKIFIER_TOOLS replaces the tools line; the block's disable line still applies. + let got = replies(&mcp_in(&dir, &[("WIKIFIER_TOOLS", "all")], &[LIST])); + assert_eq!( + names_of(&got[0]), + tools_in(&["core", "notes", "health", "map", "status"]) + ); +} + +#[test] +fn block_mistakes_are_warnings_not_failures() { + let dir = project("warn"); + write_agents( + &dir, + "wikifier: disable lokcs\nwikifier: tools core, health\nwikifier: color blue", + ); + let out = mcp_in(&dir, &[], &[INIT, LIST]); + assert!(out.status.success()); + let got = replies(&out); + let text = instructions_of(&got[0]); + let lines: Vec<&str> = text.lines().collect(); + assert_eq!(lines.len(), 3, "{text}"); + assert_eq!( + lines[0], + r#"AGENTS.md agent-tools: unknown key "color" for wikifier; write "wikifier: tools " or "wikifier: disable ""# + ); + assert_eq!( + lines[1], + r#"AGENTS.md agent-tools: unknown group "lokcs" for wikifier; groups: core, notes, health, map, cycles, status"# + ); + assert!(lines[2].starts_with("Wikifier tool groups on: core, health;")); + // The bad disable line is ignored; the good tools line still applies. + assert_eq!(names_of(&got[1]), tools_in(&["core", "health"])); + + write_agents(&dir, "wikifier: disable core"); + let got = replies(&mcp_in(&dir, &[], &[INIT, LIST])); + assert!(instructions_of(&got[0]).starts_with( + r#"AGENTS.md agent-tools: "core" cannot be disabled for wikifier, group "core" is always on; groups:"# + )); + assert_eq!(names_of(&got[1]).len(), MCP_TOOLS.len()); +} + +#[test] +fn no_block_leaves_every_reply_as_before() { + let dir = project("noblock"); + let list = r#"{"jsonrpc":"2.0","id":2,"method":"tools/list"}"#; + let bare = mcp_in(&dir, &[], &[INIT, list]).stdout; + std::fs::write( + dir.join("AGENTS.md"), + "# Agents\n\n```text\nwikifier: disable notes\n```\n\n````markdown\n```agent-tools\nwikifier: disable notes\n```\n````\n", + ) + .unwrap(); + assert_eq!(mcp_in(&dir, &[], &[INIT, list]).stdout, bare); + let golden = std::fs::read_to_string( + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/mcp_default_5.1.0.jsonl"), + ) + .unwrap() + .replace("\r\n", "\n") + .replace( + "\"version\":\"5.1.0\"", + &format!("\"version\":\"{}\"", env!("CARGO_PKG_VERSION")), + ); + assert_eq!(String::from_utf8_lossy(&bare), golden); +} + +#[test] +fn editing_the_block_mid_session_sends_list_changed() { + use std::io::{BufRead, BufReader}; + let dir = project("live"); + write_agents(&dir, "wikifier: disable map"); + let mut child = server(&dir, &[]).spawn().unwrap(); + let mut stdin = child.stdin.take().unwrap(); + let mut stdout = BufReader::new(child.stdout.take().unwrap()); + let mut send = |line: &str| { + writeln!(stdin, "{line}").unwrap(); + stdin.flush().unwrap(); + }; + let mut recv = || { + let mut line = String::new(); + stdout.read_line(&mut line).unwrap(); + jsonutil::parse(line.trim()).unwrap() + }; + send(INIT); + recv(); + send(LIST); + assert_eq!(names_of(&recv()).len(), MCP_TOOLS.len() - 3); + + write_agents(&dir, "wikifier: disable map, cycles, status"); + send(LIST); + let notice = recv(); + assert_eq!( + notice.get("method").and_then(|m| m.as_str()), + Some("notifications/tools/list_changed"), + "{notice}" + ); + assert!(notice.get("id").is_none()); + assert_eq!(names_of(&recv()), tools_in(&["core", "notes", "health"])); + + // A change that leaves the tool list as it is sends no notification. + write_agents( + &dir, + "wikifier: disable status, map , cycles # same groups", + ); + send(LIST); + let reply = recv(); + assert_eq!(reply.get("id"), Some(&Json::Int(1)), "{reply}"); + drop(stdin); + child.wait().unwrap(); +} + +#[test] +fn the_parser_reads_only_the_first_agent_tools_fence() { + use wikifier::mcp_groups::AgentTools; + let parsed = AgentTools::parse( + "````markdown\n```agent-tools\nwikifier: disable notes\n```\n````\n\n~~~agent-tools\nWikifier: tools core, health\nwikifier: disable cycles # off\nwikifier: disable status\n~~~\n```agent-tools\nwikifier: disable map\n```\n", + ); + assert!(parsed.found); + assert_eq!(parsed.tools.as_deref(), Some("core,health")); + assert_eq!(parsed.disable.as_deref(), Some("cycles,status")); + assert!(parsed.warnings.is_empty()); + assert_eq!(AgentTools::parse("no block here"), AgentTools::default()); +} From d6d0fde30c029e43501768121e0885a1c25eb666 Mon Sep 17 00:00:00 2001 From: IronAdamant <18153828+IronAdamant@users.noreply.github.com> Date: Thu, 5 Nov 2026 17:26:38 +1100 Subject: [PATCH 2/5] Release 5.2.0: tool groups and "Choosing groups" docs. Version 5.2.0 in Cargo.toml/Cargo.lock and the docs that name it. CHANGELOG "5.2.0 - 2026-11-05". README gets "Tool groups" (table, overlaps, env example, sizes) and "Choosing groups"; AGENTS.md and skills/run.md get "Choosing groups": what each group is for, when to turn it off, and the line to add. Wikifier's own AGENTS.md shows the lines in a text fence, not an agent-tools block, so dogfooding here keeps every tool. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CMYkogM3QWVjMLzWKGyjuJ --- AGENTS.md | 29 ++++++++++++++++++++++- AGENTS.md.wiki.md | 2 +- CHANGELOG.md | 8 +++++++ CLAUDE.md | 6 ++--- CLAUDE.md.wiki.md | 2 +- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 54 +++++++++++++++++++++++++++++++++++++++---- README.md.wiki.md | 2 +- skills/run.md | 32 ++++++++++++++++++++++--- skills/run.md.wiki.md | 2 +- 11 files changed, 124 insertions(+), 17 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6800eb9..91b24ff 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # AGENTS.md -Entry point for any coding agent working in this repository, or using Wikifier on another tree. The day-to-day contract is `skills/run.md` (Agent Protocol v0.7, package 5.1.0). Read that file before substantive work. This file says what is live, what is history, and which rules are easy to miss. +Entry point for any coding agent working in this repository, or using Wikifier on another tree. The day-to-day contract is `skills/run.md` (Agent Protocol v0.7, package 5.2.0). Read that file before substantive work. This file says what is live, what is history, and which rules are easy to miss. ## What this program is @@ -26,6 +26,33 @@ Many files: `wikifier record-changes -r "path/or/glob=why" --only - Prefer the CLI when the connected MCP server is still `python3 -m wikifier.mcp.server` or `wikifier-mcp`. Those entry points belong to the archived package and the handshake fails. Pass `project_root=` on every MCP call for a tree that is not the server's cwd. +## Choosing groups + +You, the agent, choose which Wikifier tool groups a project needs. Add one line for `wikifier` to the `agent-tools` block of the project's AGENTS.md: a fenced code block whose info string is `agent-tools`, in the project root the server uses (`WIKIFIER_PROJECT_ROOT`, else its working directory). The server re-reads the file when it changes and tells the client the tool list changed, so no restart is needed. `WIKIFIER_TOOLS` / `WIKIFIER_DISABLE` in the server's environment override the line, key by key. A mistake in the line is reported as a warning in the `initialize` instructions and the line is ignored. + +| Group | What it is for | Turn it off when | +|---|---|---| +| `core` | bootstrap, lookups, dependencies, file wikis, `update_maps` | never: always on | +| `notes` | `record_change` and the journal: why each file changed, handoff reasons | another tool keeps the change notes (for example Trammel notes) and you do not maintain wikis | +| `health` | `check_changes`, `mark_green`, wiki verification | you only look things up and do not maintain wikis | +| `map` | import-resolution and barrel diagnostics | you are not debugging the import map (most sessions) | +| `cycles` | the import-cycle report | you are not untangling dependencies | +| `status` | repeats of bootstrap: project status, issues, the tool catalogue | almost always | + +This repository has no `agent-tools` block, so it keeps every tool for dogfooding. The lines below go inside a block fenced with ```` ```agent-tools ```` in the target project. + +One agent maintaining wikis (the usual case): + +```text +wikifier: disable map, cycles, status +``` + +Lookups only: + +```text +wikifier: tools core +``` + ## Hard rules - `Cargo.toml` keeps an empty `[dependencies]` list. Do not add a crates.io crate, a Python package, or a Node module. diff --git a/AGENTS.md.wiki.md b/AGENTS.md.wiki.md index f300bcd..9be986e 100644 --- a/AGENTS.md.wiki.md +++ b/AGENTS.md.wiki.md @@ -2,4 +2,4 @@ **Role:** Entry point for any coding agent in this repository. -It points at `skills/run.md` (protocol v0.7, package 5.1.0) and names the live Rust binary, the daily loop, and the Python-era records kept under `Findings/archive/`. `pip install wikifier` is the archived Python 4.7 package. Map roots stay `src/` and `tests/`. The import scan stays comment-masked regex plus named re-exports. Rust also resolves `crate::`, `self::`, `super::`, root crate names, and `[workspace] members`, so `src/main.rs` and `tests/*.rs` are dependents of the library modules they import. `mark-green` checks Rust `pub` names, impl methods, and trait-impl items. +It points at `skills/run.md` (protocol v0.7, package 5.2.0) and names the live Rust binary, the daily loop, and the Python-era records kept under `Findings/archive/`. `pip install wikifier` is the archived Python 4.7 package. Map roots stay `src/` and `tests/`. The import scan stays comment-masked regex plus named re-exports. Rust also resolves `crate::`, `self::`, `super::`, root crate names, and `[workspace] members`, so `src/main.rs` and `tests/*.rs` are dependents of the library modules they import. `mark-green` checks Rust `pub` names, impl methods, and trait-impl items. A "Choosing groups" section tells an agent what each MCP tool group is for, when to turn it off, and the `wikifier:` line for the `agent-tools` block; this file itself has no such block, so dogfooding keeps every tool. diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d35231..8f6546c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [5.2.0] - 2026-11-05 + +### Added +- MCP tool groups, following the suite-wide convention. Every tool is in one of six groups: `core` (always on), `notes`, `health`, `map`, `cycles`, `status`. `WIKIFIER_TOOLS` (allowlist) and `WIKIFIER_DISABLE` (applied after it) take group or tool names, ignore case and spaces, and `WIKIFIER_TOOLS` accepts `all`. Switched-off tools are absent from `tools/list`; calling one returns `isError` with `tool "" is disabled (group "") by ; …`. An unknown name, or `core` or one of its tools in `WIKIFIER_DISABLE`, prints one line to stderr and exits 2. An empty or whitespace-only value counts as unset. When either variable is set, `initialize` carries an `instructions` line naming the active groups and `list_core_tools` adds a `groups` line and lists only the exposed tools. With neither set, every MCP reply is byte-identical to 5.1.0. The CLI ignores both variables. +- Agents choose the groups per project: the first fenced `agent-tools` block in AGENTS.md at the server's project root (`WIKIFIER_PROJECT_ROOT`, else the working directory) may hold `wikifier: tools ` and `wikifier: disable ` lines (commas or spaces, `#` comments, other tools' lines ignored). `WIKIFIER_TOOLS` overrides the `tools` line and `WIKIFIER_DISABLE` the `disable` line. A mistake in the block (unknown name, `core` in `disable`, unknown key) never stops the server: that line is ignored and a warning line goes into the `initialize` instructions and `list_core_tools`. The server stats AGENTS.md (mtime and size) before every request; when the exposed tool list changes it sends `notifications/tools/list_changed` before the response. With a block or a switch present, `initialize` advertises `tools.listChanged` and its instructions end with the groups line. With neither, replies are byte-identical to 5.1.0, so a client only learns about `listChanged` once a block exists at startup. +- "Choosing groups" sections in AGENTS.md, README, and `skills/run.md`: what each group is for, when to turn it off, and the line to add. This repository's own AGENTS.md has no block, so dogfooding keeps every tool. +- `tools/list` sizes: 22.7 KB (31 tools) with every group on; 18.2 KB without `notes`, 17.0 KB without `health`, 20.8 KB without `map`, 21.9 KB without `cycles`, 19.4 KB without `status`; 16.8 KB (22 tools) with the recommended `WIKIFIER_DISABLE=map,cycles,status`; 6.6 KB (8 tools) with `WIKIFIER_TOOLS=core`. + ## [5.1.0] - 2026-11-05 Agent-facing fixes found by driving the MCP server like an agent on real repositories, Windows fixes, and a speed pass. Protocol stays v0.7. diff --git a/CLAUDE.md b/CLAUDE.md index 4d2c9d3..852c1eb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Wikifier is a **zero-dependency, agent-to-agent codebase wiki**: it gives AI agents a token-efficient, queryable map of a codebase (health matrix, dependency graph, per-file wiki summaries) so they can look things up instead of re-reading full sources. The human layer (`index.html` dashboard) is strictly secondary — a read-only viewer of the same artifacts. It is deliberately NOT a general human documentation tool. -**This repo dogfoods itself.** Wikifier runs on its own source, and you are expected to follow its agent protocol when working here (see below). `AGENTS.md` is the entry point for any coding agent. The authoritative contract is `skills/run.md` (Agent Protocol v0.7, package 5.1.0). Read it before substantive work. +**This repo dogfoods itself.** Wikifier runs on its own source, and you are expected to follow its agent protocol when working here (see below). `AGENTS.md` is the entry point for any coding agent. The authoritative contract is `skills/run.md` (Agent Protocol v0.7, package 5.2.0). Read it before substantive work. **USE WIKIFIER FIRST (non-negotiable in this repo, preferred on any managed target):** At session start call `session_bootstrap` (MCP or `wikifier session-bootstrap`). Prefer Core daily tools (`list_core_tools`): bootstrap, `check_changes`, `prepare_edit`, `suggest_next_actions` (json `actions[]`), `record_change`, `mark_green`. Look up via map/wiki/deps before re-reading full sources. Selective work only (🔴 / actionable 🟡). Never skip `record_change` after edits. @@ -56,7 +56,7 @@ wikifier mcp # MCP server on stdio ## Architecture -Pipeline: **scan → parse → resolve → cache → health → artifacts**, implemented in Rust under `src/` (version in `Cargo.toml`, currently **5.1.0**). The Python package is no longer in this repository. `pip install wikifier` still installs Python 4.7. CLI (`src/main.rs`) and MCP (`src/mcp.rs`) both call `src/api.rs`. Every function returns a JSON object with `success`. Operational failures return `{"success": false, "error", "error_type"}`. +Pipeline: **scan → parse → resolve → cache → health → artifacts**, implemented in Rust under `src/` (version in `Cargo.toml`, currently **5.2.0**). The Python package is no longer in this repository. `pip install wikifier` still installs Python 4.7. CLI (`src/main.rs`) and MCP (`src/mcp.rs`) both call `src/api.rs`. Every function returns a JSON object with `success`. Operational failures return `{"success": false, "error", "error_type"}`. - `src/api.rs` — the library surface: `session_bootstrap`, `check_changes`, `prepare_edit`, `suggest_next_actions`, `record_change`, `record_changes`, `record_deletion`, `mark_green`, `verify_wikis`, `update_maps` / `update_maps_run`, `dependency_report`, `load_dependents`, `cycles`, `init_project`, `serve_loop`, `monitor_loop`, `daemon_ctl`. `check_changes` watches mapped files, Green files, and `monitored_paths.txt`. `record_changes` reads `git status` (git is optional). - `src/scope.rs` — project root, `map_paths.txt`, `monitored_paths.txt`, excludes, and the file walk. A missing configured map directory is a scope error. Three or more child projects make the root a container and the walk stops. @@ -65,7 +65,7 @@ Pipeline: **scan → parse → resolve → cache → health → artifacts**, imp - `src/artifacts.rs` — `file_health.json` (schema version 2) plus the `file_health.md` view, pending lines, and the journal. Identical journal retries within 120 seconds are skipped. `mark_green` stores `public_symbols`, `wiki_hash`, and `source_mtime_ns`, and refuses a Python or JS/TS wiki that misses the current public names, still mentions a removed name in backticks, or is unchanged after the public surface changed. - `src/maps_out.rs` — `library.md` (a file tree, a Mermaid block capped at 80 edges, and the dependency table) and sharded folder cards at `.wikifier_staging/maps/_root.json` and `maps/{prefix}/_index.json`. - `src/project_lock.rs` — advisory lock `.wikifier_staging/.lock`, taken before the cache lock, re-entrant per thread, 30 second wait, stolen when the recorded pid is dead. -- `src/mcp.rs` — stdio JSON-RPC. `isError` follows `success: false`. `resources/read` and `prompts/get` are implemented. Deadline `WIKIFIER_MCP_DEADLINE_S` (default 60). +- `src/mcp.rs` — stdio JSON-RPC. `isError` follows `success: false`. `src/mcp_groups.rs` holds the tool groups, the AGENTS.md `agent-tools` block parser, and the `WIKIFIER_TOOLS` / `WIKIFIER_DISABLE` switches (MCP only; an env mistake exits 2, a block mistake is a warning). This repo's AGENTS.md has no `agent-tools` block on purpose: dogfooding keeps every tool. `resources/read` and `prompts/get` are implemented. Deadline `WIKIFIER_MCP_DEADLINE_S` (default 60). Generated artifacts (in the target project root): `file_health.md/.json`, `library.md`, `pending_updates.md`, `journal/YYYY/MM/DD.md`, per-file `*.wiki.md`, `.wikifier_staging/` (`wk_cache`, folder maps, `incremental_status.json`, locks, daemon state). Scoping: `monitored_paths.txt` (extra watch list), `map_paths.txt` (import-map roots), `exclude_patterns.txt`. This repo's map roots are `src/` and `tests/`. diff --git a/CLAUDE.md.wiki.md b/CLAUDE.md.wiki.md index de3bfb6..db790fa 100644 --- a/CLAUDE.md.wiki.md +++ b/CLAUDE.md.wiki.md @@ -2,4 +2,4 @@ **Role:** Repo guidance for an agent working in this tree. -Hard constraints: empty Cargo dependencies, no hand-edits of `library.md` or the health and pending files, and the human dashboard stays secondary. The Python-era plan logs live under `Findings/archive/`. It points agents at `AGENTS.md` and `skills/run.md` (protocol v0.7, package 5.1.0). The architecture section names the Rust modules under `src/`, the library file tree, and this repo's map roots `src/` and `tests/`. The parse note includes Rust `crate::`, `self::`, `super::`, Cargo.toml crate names, `[workspace] members`, and `rust_public_symbols` for wiki checks. JSON failures use `success: false`. +Hard constraints: empty Cargo dependencies, no hand-edits of `library.md` or the health and pending files, and the human dashboard stays secondary. The Python-era plan logs live under `Findings/archive/`. It points agents at `AGENTS.md` and `skills/run.md` (protocol v0.7, package 5.2.0). The architecture section names the Rust modules under `src/`, the library file tree, and this repo's map roots `src/` and `tests/`. The parse note includes Rust `crate::`, `self::`, `super::`, Cargo.toml crate names, `[workspace] members`, and `rust_public_symbols` for wiki checks. JSON failures use `success: false`. diff --git a/Cargo.lock b/Cargo.lock index f00ad76..006b0c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,4 +4,4 @@ version = 4 [[package]] name = "wikifier" -version = "5.1.0" +version = "5.2.0" diff --git a/Cargo.toml b/Cargo.toml index 5c8fc61..21067c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wikifier" -version = "5.1.0" +version = "5.2.0" edition = "2021" description = "Wikifier — zero-dependency agent-to-agent codebase wiki." license = "MIT" diff --git a/README.md b/README.md index 46b94a4..5964446 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ Download a binary from the [GitHub releases](https://github.com/IronAdamant/wiki Check `SHA256SUMS`, unpack, and put `wikifier` (`wikifier.exe` on Windows) on your `PATH`: ```bash -# Linux x86_64, 5.1.0 -curl -fsSL -O https://github.com/IronAdamant/wikifier/releases/download/v5.1.0/SHA256SUMS -curl -fsSL -O https://github.com/IronAdamant/wikifier/releases/download/v5.1.0/wikifier-5.1.0-x86_64-unknown-linux-gnu.tar.gz +# Linux x86_64, 5.2.0 +curl -fsSL -O https://github.com/IronAdamant/wikifier/releases/download/v5.2.0/SHA256SUMS +curl -fsSL -O https://github.com/IronAdamant/wikifier/releases/download/v5.2.0/wikifier-5.2.0-x86_64-unknown-linux-gnu.tar.gz sha256sum --check --ignore-missing SHA256SUMS -tar -xzf wikifier-5.1.0-x86_64-unknown-linux-gnu.tar.gz +tar -xzf wikifier-5.2.0-x86_64-unknown-linux-gnu.tar.gz ./wikifier --version ``` @@ -60,6 +60,52 @@ Or add it to a project's `.mcp.json`: Every tool takes `project_root` (an absolute path). Without it the server uses `WIKIFIER_PROJECT_ROOT`, then its working directory. A call with a missing argument or an unknown file fails with a message that names the fix, and a failed call sets `isError`. To keep replies small, MCP `session_bootstrap` lists at most 100 files unless you pass `limit` (`files_total` gives the full count, `limit: 0` lists every file), and `update_maps` leaves out the edge list unless you pass `edges: true`. Then give the agent the short prompt in [`skills/run.md`](skills/run.md#paste-into-new-sessions). Any agent that can run shell commands can use the CLI instead: the daily tools have twins such as `wikifier session-bootstrap`, `prepare-edit`, and `record-change` that print the same JSON (the mapping is in `skills/run.md`). +### Tool groups + +The 31 MCP tools are in six groups. The agent picks the groups a project needs with one line in the project's AGENTS.md (see Choosing groups below); an operator can override that in the MCP client's `env` block. The CLI is not affected. `WIKIFIER_TOOLS` is an allowlist and `WIKIFIER_DISABLE` hides groups or single tools after it; both take comma-separated group or tool names, ignore case and spaces, and `WIKIFIER_TOOLS` also accepts `all`. With neither set, the listing is exactly what it was. An unknown name, or `core` or one of its tools in `WIKIFIER_DISABLE`, stops the server with exit code 2 and a one-line message, so a mistake shows up as a failed server. An empty value counts as unset. A switched-off tool, if called, returns `isError` naming the switch to change. + +| Group | Tools | Overlaps with | +|---|---|---| +| `core` (always on) | `session_bootstrap`, `prepare_edit`, `get_dependencies`, `get_dependents`, `get_file_wiki`, `list_paths`, `suggest_next_actions`, `update_maps` | — | +| `notes` | `record_change`, `record_changes`, `record_deletion`, `search_journal`, `why_file`, `journal` | Trammel notes (`add_note`) | +| `health` | `check_changes`, `mark_green`, `verify_wikis`, `health`, `validate`, `list_healable_stubs`, `heal_stubs`, `seed_source_content_hashes` | — | +| `map` | `get_resolution_diagnostics`, `get_barrel_reports`, `get_incremental_status` | — | +| `cycles` | `get_cycles` | — | +| `status` | `list_core_tools`, `get_project_status`, `get_current_project_root`, `issues`, `get_files_needing_attention` | — | + +`tools/list` is 22.7 KB with every group on. The recommended lean setting keeps the whole daily loop and drops the diagnostics and the tools that repeat bootstrap: 22 tools, 16.8 KB. + +```json +"env": {"WIKIFIER_DISABLE": "map,cycles,status"} +``` + +`WIKIFIER_TOOLS=core` alone is 8 tools and 6.6 KB, for an agent that only looks things up. Turning `notes` off also turns off `record_change`, which marks a file for its wiki refresh, so keep `notes` on unless another tool records the changes. + +### Choosing groups + +You, the agent, choose which Wikifier tool groups a project needs. Add one line for `wikifier` to the `agent-tools` block of the project's AGENTS.md: a fenced code block whose info string is `agent-tools`, in the project root the server uses (`WIKIFIER_PROJECT_ROOT`, else its working directory). The server re-reads the file when it changes and tells the client the tool list changed, so no restart is needed. `WIKIFIER_TOOLS` / `WIKIFIER_DISABLE` in the server's environment override the line, key by key. A mistake in the line is reported as a warning in the `initialize` instructions and the line is ignored. + +| Group | What it is for | Turn it off when | +|---|---|---| +| `core` | bootstrap, lookups, dependencies, file wikis, `update_maps` | never: always on | +| `notes` | `record_change` and the journal: why each file changed, handoff reasons | another tool keeps the change notes (for example Trammel notes) and you do not maintain wikis | +| `health` | `check_changes`, `mark_green`, wiki verification | you only look things up and do not maintain wikis | +| `map` | import-resolution and barrel diagnostics | you are not debugging the import map (most sessions) | +| `cycles` | the import-cycle report | you are not untangling dependencies | +| `status` | repeats of bootstrap: project status, issues, the tool catalogue | almost always | + +One agent maintaining wikis (the usual case): + +```agent-tools +wikifier: disable map, cycles, status +``` + +Lookups only: + +```agent-tools +wikifier: tools core +``` + ## Quick start ```bash diff --git a/README.md.wiki.md b/README.md.wiki.md index 31239a4..6c49919 100644 --- a/README.md.wiki.md +++ b/README.md.wiki.md @@ -2,4 +2,4 @@ **Role:** The public entry point for the std-only Rust program. -Order: what it is, install (release archive `wikifier--` plus `SHA256SUMS`, or `cargo build --release`), connecting an agent over MCP (`claude mcp add wikifier -- wikifier mcp` or `.mcp.json`, `project_root` on every call), a quick start of the edit loop, how it works (pipeline, artifacts, language table), then the measured Performance and Benchmarks tables (unchanged; the Performance table says its numbers are from the Python package), the dashboard, and links. Detail lives in `skills/run.md` (protocol v0.7, package 5.0.0) and `AGENTS.md`. `pip install wikifier` still installs Python 4.7. +Order: what it is, install (release archive `wikifier--` plus `SHA256SUMS`, or `cargo build --release`), connecting an agent over MCP (`claude mcp add wikifier -- wikifier mcp` or `.mcp.json`, `project_root` on every call), a quick start of the edit loop, how it works (pipeline, artifacts, language table), then the measured Performance and Benchmarks tables (unchanged; the Performance table says its numbers are from the Python package), the dashboard, and links. Detail lives in `skills/run.md` (protocol v0.7, package 5.0.0) and `AGENTS.md`. `pip install wikifier` still installs Python 4.7. The MCP section has "Tool groups" (the six groups, env switches, sizes) and "Choosing groups" (the `agent-tools` block line an agent adds to AGENTS.md). diff --git a/skills/run.md b/skills/run.md index 215e100..52118d7 100644 --- a/skills/run.md +++ b/skills/run.md @@ -1,6 +1,6 @@ # Wikifier Agent Protocol v0.7 -**Package 5.1.0** (live version: `wikifier --version`, from `Cargo.toml`) · **Status:** active, supersedes v0.6 · **Scope:** agent-to-agent codebase wiki for token-efficient lookup. Not a human docs product, not an issue tracker. +**Package 5.2.0** (live version: `wikifier --version`, from `Cargo.toml`) · **Status:** active, supersedes v0.6 · **Scope:** agent-to-agent codebase wiki for token-efficient lookup. Not a human docs product, not an issue tracker. This file is the contract for any agent operating Wikifier. Part 1 is all you need day to day; Part 2 is reference. In the Wikifier repository, `AGENTS.md` is the entry point and points here. @@ -39,10 +39,35 @@ This file is the contract for any agent operating Wikifier. Part 1 is all you ne 2. Write `map_paths.txt` (import-map package roots; independent of monitored paths). 3. `update_maps(full=True)`, then re-run `session_bootstrap`. +### Choosing groups + +You, the agent, choose which Wikifier tool groups a project needs. Add one line for `wikifier` to the `agent-tools` block of the project's AGENTS.md: a fenced code block whose info string is `agent-tools`, in the project root the server uses (`WIKIFIER_PROJECT_ROOT`, else its working directory). The server re-reads the file when it changes and tells the client the tool list changed, so no restart is needed. `WIKIFIER_TOOLS` / `WIKIFIER_DISABLE` in the server's environment override the line, key by key. A mistake in the line is reported as a warning in the `initialize` instructions and the line is ignored. + +| Group | What it is for | Turn it off when | +|---|---|---| +| `core` | bootstrap, lookups, dependencies, file wikis, `update_maps` | never: always on | +| `notes` | `record_change` and the journal: why each file changed, handoff reasons | another tool keeps the change notes (for example Trammel notes) and you do not maintain wikis | +| `health` | `check_changes`, `mark_green`, wiki verification | you only look things up and do not maintain wikis | +| `map` | import-resolution and barrel diagnostics | you are not debugging the import map (most sessions) | +| `cycles` | the import-cycle report | you are not untangling dependencies | +| `status` | repeats of bootstrap: project status, issues, the tool catalogue | almost always | + +One agent maintaining wikis (the usual case): + +```agent-tools +wikifier: disable map, cycles, status +``` + +Lookups only: + +```agent-tools +wikifier: tools core +``` + ### Paste into new sessions ``` -You are operating inside a Wikifier-managed codebase (Agent Protocol v0.7, package 5.1.0). +You are operating inside a Wikifier-managed codebase (Agent Protocol v0.7, package 5.2.0). It is an agent-to-agent wiki: look things up (health, file wikis, deps) instead of re-reading sources. SELECTIVE WORK: only update 🔴 Red and actionable 🟡 Yellow files; never re-wiki 🟢 Green files; @@ -147,7 +172,7 @@ The implementation is a std-only Rust binary. `wikifier.sh` / `.ps1` / `.bat` la There is no Python library. Agents call the CLI or `wikifier mcp`. The same functions live in the Rust crate (`src/api.rs`) and both fronts call them. -### Implementation (package 5.1.0, protocol stays v0.7) +### Implementation (package 5.2.0, protocol stays v0.7) The program is a std-only Rust binary under `src/`. `Cargo.toml` has an empty `[dependencies]` list. Launchers exec that binary. MCP is `wikifier mcp`. @@ -163,6 +188,7 @@ The program is a std-only Rust binary under `src/`. `Cargo.toml` has an empty `[ - `seed-source-hashes` writes the current hash onto Green rows and does not change status. `--force` replaces a hash that is already stored. `seed-health` still adds Initial-stub rows. `heal-stubs` promotes a stub whose wiki is at least 350 characters (`--min-wiki-length` overrides). - Health stubs from `update-maps` follow `monitored_paths.txt` when that file lists real paths. If the file is absent, empty, or only a bare `.`, every mapped file is seeded. - The scan ignores comments and strings. It does not use CPython `ast`. It does read `tsconfig.json` `paths`, `package.json` `exports`, and npm `workspaces` (`*` directory globs). Named re-exports are the barrel follow. Rust reads the root `Cargo.toml` `[package].name`, `[lib].name`, and `[workspace] members` (globs included; hyphens become underscores). It resolves `crate::`, `self::`, `super::`, those crate names, and `mod` to files. `crate::` stays in the file's crate (`tests/*.rs` and `src/bin/*.rs` are their own crates, and a workspace member does not share `crate::` with another member). A package or lib name points at that member's library. Accuracy is `accuracy_fixtures_match_frozen_edges`, including the Rust crate layout. This parser has not been run on Babylon.js. +- MCP tools are in groups (`core` always on, `notes`, `health`, `map`, `cycles`, `status`; the table is in the README). `WIKIFIER_TOOLS` / `WIKIFIER_DISABLE` in the server's environment hide groups or single tools from `tools/list`; a hidden tool called anyway returns `isError` naming the switch. An unknown name, or `core` in `WIKIFIER_DISABLE`, stops the server (exit 2). A recommended lean setting is `WIKIFIER_DISABLE=map,cycles,status`, which keeps the whole session loop. - MCP `tools/call` sets `isError` when the payload has `success: false`. `resources/read` and `prompts/get` answer. Prompts name the tools to call. Optional arguments include `format` (`text` or `json`), `timeout_s`, `directory`, `detail`, `low_confidence_only`, `unresolved_only`, `depth`, `recursive`, `max_files`, `limit`, `max_items`, and a `reasons` object. A call waits at most `timeout_s` or `WIKIFIER_MCP_DEADLINE_S` seconds (default 60) and then returns `timed_out` and `may_still_complete`. An identical journal action, file, and reason inside 120 seconds sets `duplicate_skipped` and does not append another line. A call that leaves out a required argument other than `project_root` returns `error_type: "InvalidArguments"` with the accepted and received argument names. Over MCP, `update_maps` omits the edge list unless `edges: true` (`edges_persisted` is the count), and `health` takes `limit` (with `entries_total`) and `summary`. The CLI default is JSON. `--text` prints prose. `health --format text` does the same for health. - Commands that write health, pending, the map, or the cache take `.wikifier_staging/.lock` before the cache lock. The lock is re-entrant on the same thread, waits 30 seconds, and is stolen when the recorded pid is dead. A timeout returns `error_type: "LockTimeoutError"` and `timed_out: true`. - `init` keeps a path list that already has a non-comment entry. When a list is missing it writes the map roots: `src/` when it exists, otherwise every top-level directory that holds a source file (for example `crates/` and `tests/` in a Cargo workspace), otherwise `src/`. It also writes `exclude_patterns.txt`, empty `file_health.md`, `pending_updates.md`, `library.md`, `.wikifier/config`, `.wikifier/marker`, and the `journal/` and `Logged_issues/` directories when those paths are absent. `--no-copy` skips `index.html`. Otherwise `index.html` is copied only when it is missing. diff --git a/skills/run.md.wiki.md b/skills/run.md.wiki.md index 84b8bd5..b451258 100644 --- a/skills/run.md.wiki.md +++ b/skills/run.md.wiki.md @@ -4,4 +4,4 @@ Part 1 is the session loop: bootstrap, check-changes, suggest-next, prepare-edit, record-change, mark-green, update-maps. Part 2 is the reference for health, wiki verification, batch recording, dependencies, and commands. Wiki verification covers Python, JS/TS, and Rust `pub` items including impl methods and trait-impl items. Rust import names include `[workspace] members`. -The implementation note records how the std-only Rust binary fills that contract: `wk_cache`, regex-plus-reexport parsing, Rust paths from `crate::` / `self::` / `super::` / the root Cargo.toml crate name, map artifacts, deletion, MCP errors, the project lock, and a standing `serve` that feeds the dashboard. Daemon actions are `start`, `stop`, `status`, and `run`. `init DIR`, `verify-wikis DIR`, and `search-journal --file` apply. `init` seeds the map roots it finds. File arguments may use `\` separators. Lookups on an unknown path return `FileNotFound`; an MCP call missing a required argument returns `InvalidArguments`; MCP `update_maps` leaves out the edge list unless `edges: true`. The protocol version stays v0.7. The package line is 5.1.0. The live version command is `wikifier --version` (from `Cargo.toml`). +The implementation note records how the std-only Rust binary fills that contract: `wk_cache`, regex-plus-reexport parsing, Rust paths from `crate::` / `self::` / `super::` / the root Cargo.toml crate name, map artifacts, deletion, MCP errors, the project lock, and a standing `serve` that feeds the dashboard. Daemon actions are `start`, `stop`, `status`, and `run`. `init DIR`, `verify-wikis DIR`, and `search-journal --file` apply. `init` seeds the map roots it finds. File arguments may use `\` separators. Lookups on an unknown path return `FileNotFound`; an MCP call missing a required argument returns `InvalidArguments`; MCP `update_maps` leaves out the edge list unless `edges: true`. The protocol version stays v0.7. The package line is 5.2.0. The live version command is `wikifier --version` (from `Cargo.toml`). From 290a8181749a9ae9bf28174ce2f0a15f2b42f1a9 Mon Sep 17 00:00:00 2001 From: IronAdamant <18153828+IronAdamant@users.noreply.github.com> Date: Thu, 5 Nov 2026 17:26:39 +1100 Subject: [PATCH 3/5] Dogfood: record the tool-groups work in the repo's wiki state. Generated by the wikifier binary (record-change, mark-green, update-maps), not edited by hand. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CMYkogM3QWVjMLzWKGyjuJ --- file_health.json | 2 +- file_health.md | 22 +++--- journal/2026/11/05.md | 156 ++++++++++++++++++++++++++++++++++++++++++ library.md | 50 +++++++------- pending_updates.md | 2 +- 5 files changed, 197 insertions(+), 35 deletions(-) diff --git a/file_health.json b/file_health.json index 893bbe2..6b39efc 100644 --- a/file_health.json +++ b/file_health.json @@ -1 +1 @@ -{"entries":{".github/workflows/publish.yml":{"last_updated":"2026-11-03 09:27:04","reason":"Multi-target release archives and SHA256SUMS (subid=release-5.0.0)","source_content_hash":"sha256:930170e1eb57afbe2850a0e9c2ac179eb2b5947bf2f74d4292bcd2b0099ab8de","source_mtime_ns":"1793697915725124882","status":"🟢 Green","verification":"no_wiki"},"AGENTS.md":{"last_updated":"2026-11-05 05:37:13","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:061e89b5c878a724b70961af111a00463bf7825d89ffa36199f670854c492d0b","source_mtime_ns":"1793856741183515200","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:566772a56a5d2658deaf7433304d296a587dacd1974ccac0e51f5311fbfa0eb2"},"CHANGELOG.md":{"last_updated":"2026-11-05 05:37:12","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:e934ea90eda41f79960d168deb7ea605cef9499f0b00a30ac3acc51ea7ddd1dc","source_mtime_ns":"1793856916335755100","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:757601288624e346279cef86383a88cdf7c1c467e7c6538f40c05d475e243de8"},"CLAUDE.md":{"last_updated":"2026-11-05 05:37:13","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:cf5400147486bb6de80ce55aa1e40019eaa135d384900fe32d9f4327bbd42a7c","source_mtime_ns":"1793856929650897400","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:b1361a7b9b66eee9ebcc41b71c3535ab4deda7ac10495a352c93f9ceb0b96708"},"CONTRIBUTING.md":{"last_updated":"2026-11-03 05:34:35","reason":"Address the 3 Nov review findings (subid=review-2026-11-03)","source_content_hash":"sha256:d090280cd3d1c3ab1cf342d69392471ed3835512ff7381bf4409bada57bbe89c","source_mtime_ns":"1793683924316411256","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:ec0bd9342b8e9dfeefaabc8dcddeb577f6bd4f1c760d7286b21d709c2a372b29"},"Cargo.lock":{"last_updated":"2026-11-05 05:37:21","reason":"version 5.1.0 (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:268450875f2c013867053718dcf4691bc6bdb6e87986978c66c9c30dd5b57851","source_mtime_ns":"1793856741182515400","status":"🟢 Green","verification":"no_wiki"},"Cargo.toml":{"last_updated":"2026-11-05 05:37:20","reason":"version 5.1.0 (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:696d54c0d35dbe7d4d2bfe8243808ab3e1ca4682decd39714a2b76ae11c2405b","source_mtime_ns":"1793856741181514900","status":"🟢 Green","verification":"no_wiki"},"Findings/M5-Dogfood-Assessment-Report.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:238435188b1699e5bcf4753b62a6fe55cb064413a291259f0b696b5bd3c1692f","source_mtime_ns":"1780519956000000000","status":"🟢 Green"},"Findings/M5-Dogfood-Progress.md":{"last_updated":"2026-11-03 08:06:46","reason":"Wiki marks this file as the historical M5 log (subid=protocol-v07)","source_content_hash":"sha256:ef55167e819806060dfd7dfe7cdfd4d02024ca97706a7faa243710e2630b65fe","source_mtime_ns":"1793408707259550076","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:b6b1fa4bbee0c7e8c4035cd925f6d07e1221ba483e3472878d5b88236c5cf7f9"},"Findings/M5.1-cross-hardening-analysis.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:a2c2414e5b6c9b1a802bec8734a7924850d546cd7746a8087216f3685ca36cb4","source_mtime_ns":"1780519762000000000","status":"🟢 Green"},"Findings/Milestones-Overview.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:f8b7030ec8980774cf3a2560ad7aee6537263eadf8374e650718f7c6793c6d50","source_mtime_ns":"1780800604000000000","status":"🟢 Green"},"Findings/p6_real_world_validation_report.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:0468224675888f2747674324726c0ea9a5dddded39d9a1a50f22fc3357dafc0f","source_mtime_ns":"1780520008000000000","status":"🟢 Green"},"README.md":{"last_updated":"2026-11-05 05:37:12","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:842e32d2b29147c076979247ecd481341d592b59c96887e889c00d3a5d9ad270","source_mtime_ns":"1793856929649896000","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:45e2581fe9d69ba807dfce7e982c015e23c2702a6c765b83eb9513ef809418da"},"docs/spec.md":{"last_updated":"2026-11-03 08:00:11","reason":"Name the Rust binary and protocol v0.7 in the living principles (subid=protocol-v07)","source_content_hash":"sha256:31fe6b3b3d705628692eb0512cf44cbb21861ccfc5bb02afdd46d796ec066c6e","source_mtime_ns":"1793653008580824356","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:a58b929d25d510f15f9fe176d7823e852f6d089e398accc2e22e1ed189f260ac"},"scripts/benchmark_parity.sh":{"last_updated":"2026-11-03 08:56:15","reason":"Benchmark script and measured results.","source_content_hash":"sha256:b8f72e3245e77b9df17b303293d8cbe4a93cc36023c41b89a794b77b01daef87","status":"🟡 Yellow"},"scripts/benchmark_results.md":{"last_updated":"2026-11-03 08:56:15","reason":"Benchmark script and measured results.","source_content_hash":"sha256:8bf9342fce85f126a37f812b03b6f6997f1fe8e7c5176d30301c1a4a15aeee29","status":"🟡 Yellow"},"skills/run.md":{"last_updated":"2026-11-05 05:37:13","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:0b9b5a13be93850438c7fc0e4f5a89c59d7aabcb1984d95e1fc320467ca6f3c5","source_mtime_ns":"1793856929676891500","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:32979845d60e04b005050ff669cda3dcaf90a8cb0d2c774bda517b1e11b70a0b"},"src/api.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"MapRun\nVERSION\nMCP_TOOLS\nupdate_maps\nupdate_maps_opts\nupdate_maps_run\nseed_source_hashes\nmapped_edges\nload_dependencies\ndependency_report\nload_dependents\nlist_paths\nlist_paths_at\nsession_bootstrap\nsession_bootstrap_scoped\nsuggest_next_actions\nsuggest_next_scoped\ncheck_changes\nprepare_edit\nrecord_change\nmark_green\nhealth\nhealth_view\nread_health\nread_journal\ncache_status\nvalidate\ncycles\ncycles_view\nverify_wikis\nrecord_changes\nrecord_changes_opts\nrecord_deletion\nheal_stubs\nprune_health\nprune_health_opts\nprune_pending\nstale_wikis\nstale_wikis_in\nprune_barrels\nmetrics_snapshot\nhealing_stats\nresolution_diagnostics\nbarrel_reports\nincremental_status\nserve_once\nserve_loop\nmonitor_loop\ndaemon_ctl\ndaemon_command\ndispatch\nCLI_COMMANDS\nensure_root","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:f5575d808fab6a3334acd6af46c1f926b15156993828a21be86e7335487baab2","source_mtime_ns":"1793856867181743100","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:1959bc30bd0758cbcbef5c2c1da7bf2599b044f8f954f8d9043ca7e794590a7a"},"src/artifacts.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"HealthRow\nwrite_durable\nread_health\nwrite_health\nupsert_health_row\nJournalEntry\njournal_path\nread_journal\nparse_journal\nJournalWrite\nappend_journal\nread_pending\nfolder_card\nnew\nkeep_baseline_from","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:c5989a5fe22edf99afab4b4721fda9f45a12faff19d9f1a97277fcf1003d1ffd","source_mtime_ns":"1793856655049237400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:751e2374f151dc19c0d20ff447db2ce26b908af28067a7e74ef3a0502ce51bc2"},"src/cache.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"check_consistency\nrebuild\nConsistency\nSession\npayload_path\nby_src_path\ncommit_pending_path\nload_dependencies\nInternalEdge\nconfidence_of\nformat_edge_line\nDependencyView\nload_dependency_view\nload_internal_edges\nload_dependents\nlist_prefix\nall_paths\nFileUpdate\nupsert_file\nremove_file\nindexed_rows\nindex_by_path\nhash_if_unchanged\npayload_bytes\nstat_ns\nedges\nrel_string\nwrite_barrel_record\nprune_barrel_files\nconfidence\nacs_reason","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:d0e30e9031d1259333ebeb7799ad78c1836135fa762197d3512f7193640ed6af","source_mtime_ns":"1793856524124108400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:a48d3652a05cb7e208651c63045e714c62ba5ea1fd7e19fac3b9df84c1af31de"},"src/cache_commit.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"Consistency\nSession\ncheck_consistency\nrebuild\nopen\nknown\ndsts_of\nnote_stat\nrels\nupsert\nremove\nstage_barrel\nhas_changes\nneeds_parse\ncommit","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:fb1f90a3d27558ed141eba2d8fb408bc76a47b2c6715096dba5e75819809513f","source_mtime_ns":"1793856524408983600","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:60c2ba29a68f5feb2a5dd69b9a99d550c6d288386f2a822811eb1530742bf336"},"src/cycle_report.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:db35b610d9a9f9917805da9383e61872e66e640482f57fc9e17ae91daf77fe3d","status":"🟡 Yellow"},"src/daemon_svc.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:0887baeb3ad7f2fca851fccc0d9335dafd4b42f3e54e236175a13d39c5bcd063","status":"🟡 Yellow"},"src/jsonutil.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"Json\nparse\nparse_jsonc\nstrip_json_comments\nobj\nfrom_pairs\nget\nas_str\nas_bool\nas_array\nas_object\ninsert\nfmt","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:cb71e00e352df010928a42323d6d87bbe67348834a209348fc174b9d00489676","source_mtime_ns":"1793684429116993727","status":"🟡 Yellow","wiki_hash":"sha256:fb4cffba8b14a179dd90f201b61df2608ca78a9775e9646e7f011f1b9fa07c63"},"src/legacy_cache.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"import_if_empty","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:a127d0b1742d69b736194ca98579f5fc0611fc51a291d691aef6fe586fd68ba3","source_mtime_ns":"1793683981803718735","status":"🟡 Yellow","wiki_hash":"sha256:a6fe6c79185a46cc4b30d215475bab28f517f6e5a6fd7bce6423c2792814aac8"},"src/lib.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"api\nartifacts\ncache\njsonutil\nmaps_out\nmcp\nparse\nscope\nsha256\ntimeutil\ncache_status\ncheck_changes\nhealth\nlist_paths\nload_dependencies\nload_dependents\nmapped_edges\nmark_green\nprepare_edit\nread_health\nread_journal\nrecord_change\nsession_bootstrap\nsuggest_next_actions\nupdate_maps\nVERSION\nJson","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:9c27c83b58ff7f1acf62d5d19ee31e2070daa06499e27141cc7071fae44e26b8","source_mtime_ns":"1793678007370625780","status":"🟡 Yellow","wiki_hash":"sha256:d7e771a3ff63ab55a7967195e3b403dd75d5ae020a383adc56f0e5c09d7b03a0"},"src/low_conf.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:3ade5fc70ce585a48b9acf6a2b48753e58e80f63281a31c8b8453816700b375e","status":"🟡 Yellow"},"src/main.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:2b3cebdafca3ca3da7831101a63b36f72260b3b2879871e5364b427428e782e0","source_mtime_ns":"1793683990351610198","status":"🟡 Yellow","wiki_hash":"sha256:db6e1cd5beeb90e5a65b3e00a37ee2c73ea4c53750771151e655459a1b823ff5"},"src/maps_out.rs":{"last_updated":"2026-11-05 05:15:33","public_symbols":"current\nwrite\nwrite_status\nread_status","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:4223756e3ddd7a7317d364f5de9bbffe1fe59e820b0b8187164bd30449039432","source_mtime_ns":"1793854043821084000","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:5218571835e011f1f33b83b5a57723204910bb8209a5f88a1a2d3a06ee82e30a"},"src/mcp.rs":{"last_updated":"2026-11-05 05:15:47","public_symbols":"tool_schema\nhandle_message\nserve_stdio","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:e2c23ee73b46d74c10ede239e9e84b6d23780d3327243fb13a8ab81598fa2206","source_mtime_ns":"1793854176936293700","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:fa2b29df474b116fd21d53019c113eb9171681362d072b6e6db4a2f15b049cf4"},"src/parse.rs":{"last_updated":"2026-11-05 05:15:33","public_symbols":"RawImport\nKind\nScan\nlanguage\nread_utf8\nscan_file_warned\nscan_file\nresolve_project\nrust_public_symbols\nresolve_python_spec\nFactEdge\nFileFacts\nAnalysis\nanalyze_files\nanalyze_changed\nedges_for_files","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:4122cf1ec797e2af0a410dcf13d6cfb3f087410db5dcae27cff7c79cbdd88228","source_mtime_ns":"1793855453252350400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:3ea6562f6fbb69c3510cba443a994caa2dbab3fae30e290847ec1cd43913e047"},"src/pending_line.rs":{"last_updated":"2026-11-05 05:19:31","public_symbols":"file_of\nformat_item\nEMPTY_NOTE\nappend_item\nremove_item\nrecord_message\nCHECK_MESSAGE","reason":"wiki (claude/windows-verify pending)","source_content_hash":"sha256:f1ad66b1c330ce490b36a72d58cb2a341b0f44b0b5ec2166cd943a83cf694d05","source_mtime_ns":"1793855871596115600","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:3bac5aead2f3a0b020e056fe388d7670f9a3b45d79be75d197f5b71966620f56"},"src/proc.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:8f13798a8b9289d78913becc626056c8b016838570e356e09bfa3333e800351c","status":"🟡 Yellow"},"src/project_lock.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"ProjectLock\ndrop\nacquire","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:194e329f35ff59b11fc734b980a1ee33f8e464bcdb5eae899486e487daef3a25","source_mtime_ns":"1793678007370625780","status":"🟡 Yellow","wiki_hash":"sha256:fccc8d547f30262ff64d506d842472623e828ebe39fde71532a683c6956329d2"},"src/scope.rs":{"last_updated":"2026-11-05 05:15:34","public_symbols":"SOURCE_EXTS\nScope\ndetect\nread_path_list\nexcludes\nis_source\ncollect\nrel_of\ndefault_map_roots\nrel_arg\nallows_walk","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:0843deef3d82162edf7bac2c53c9a9f716735b4e639451f7fb36620de2dcd059","source_mtime_ns":"1793854073257790700","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:574d4cc8bd261700b1e192628435926d8f1e533f7f1967e27eb6c797e59e6c0e"},"src/sha256.rs":{"last_updated":"2026-11-05 04:14:08","public_symbols":"sha256\nsha256_hex\nsha256_prefixed\ncontent_sha256_prefixed\nfile_sha256_prefixed","reason":"wiki updated (claude/windows-verify)","source_content_hash":"sha256:2f4f8a8ccb9f9d4748fc0678e6bac63dc69ade57e9ab4b3c6eb2a1c43fcf5c14","source_mtime_ns":"1793851995838527400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:0d1d67e61bed7a20c6a8413a352a55fb87f05bda6e39760015727d128a67ae33"},"src/symbols.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:4a150ba04e9ea26020c874c5e256a9ec5acc3ef4d621fb6ff03b21935c3f8046","status":"🟡 Yellow"},"src/text_out.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:8e0edc1141a2c1745c0e6fdd7a7645c7332365fac532d52fb3e188f4ef06148e","status":"🟡 Yellow"},"src/timeutil.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:9921127144d9d40619e260753e700e9c8a47135ed95b2ad8791afb7fe78afd75","status":"🟡 Yellow"},"src/wiki_files.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:2612539ce9092a3d126d80ce2947f6b4555ddb0bb335769b1619ec67d08a5e84","status":"🟡 Yellow"},"tests/agent_args.rs":{"last_updated":"2026-11-05 04:14:08","reason":"new: agent-style file args, missing args, lean MCP outputs, init roots, CRLF (claude/windows-verify)","source_content_hash":"sha256:ae25dcc233b1d40c48dbc7199e350032717412316089084751b9280970feb66d","status":"🟡 Yellow"},"tests/behaviour_gaps.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:8c8d669dae2dbe39b88c2223d20fb2fca51ac1605c62edd108d6ef224223402b","source_mtime_ns":"1793684893298602299","status":"🟡 Yellow","wiki_hash":"sha256:b9d20a310ca48ffd858e6d0d4e49b5e0568ecb57dc5ad981eb54398562864691"},"tests/cache_and_artifacts.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:b9483666c1e19f90d4db1af718b08beebadfbcba66152497b7694d8e757a5ec1","status":"🟡 Yellow"},"tests/cli_surface.rs":{"last_updated":"2026-11-05 05:37:11","reason":"docs name the Cargo version (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:0aef6e3256a524e014971637bad8a928deba528b734995728bfb72ea606730f5","status":"🟡 Yellow"},"tests/contract_gaps.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:dc91a239bbc615524b4ac2c58d06515183dfc4981309906003f551e6721d82ae","status":"🟡 Yellow"},"tests/dogfood.rs":{"last_updated":"2026-11-05 05:15:34","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:3d0509564036285a918a0a8d720df5ec9fa0d31490c8cf16b49c16570f31f6c5","source_mtime_ns":"1793855180442138300","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:0bc5f3d78d1779ba6302ecc406dc0b25d8beda25f1681a26d57e97210df19906"},"tests/parity.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:0246038a1cc01bf66da2fd186ede61f2dcd2c98da9c0c90dd7f3b2cbab1036db","source_mtime_ns":"1793683314773282057","status":"🟡 Yellow","wiki_hash":"sha256:32753c244642df6e08f8578c6203f77225363783c15bc57c33a84f03989f2378"},"tests/parity_fixes.rs":{"last_updated":"2026-11-05 05:15:33","reason":"pending item wording and empty-queue note (claude/windows-verify speed)","source_content_hash":"sha256:b74f37dffb2a5bbcc8724298885a677a9d4476f846791d31770798e0a6caa7a3","status":"🟡 Yellow"},"tests/protocol_v07.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:bb7cffecabc3fb51ebcc77c64f7fd78f5cd15c445d7e13493ed491227280f37d","source_mtime_ns":"1793684781738827745","status":"🟡 Yellow","wiki_hash":"sha256:b38f4a13e316cefd56070f822980b4f83d9cdacb850ab1978de48ed35c630ec8"},"tests/robustness.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:fad304193a47baa8cce21cff8786b35974c7c7f6f71b3318edeb68bd60121681","status":"🟡 Yellow"},"tests/skip_maps.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:2eed0c6bc97d91a4be3f2b6ab08c78c62a3a05725a503496e3df91abad6b2130","status":"🟡 Yellow"},"tests/speed_paths.rs":{"last_updated":"2026-11-05 05:37:11","reason":"self-heal and durable user-state tests (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:a9348e032c3ffd9f6960710b364470cbcbf935f366af604dd2ad62ac4f2a7a9e","status":"🟡 Yellow"},"wikifier.sh":{"last_updated":"2026-11-03 08:06:46","reason":"Wiki describes the Rust binary launcher (subid=protocol-v07)","source_content_hash":"sha256:4f467e2117e8c361882054998cb0506717d9555e2aa570f0e176fc18d9c2f4aa","source_mtime_ns":"1793410024331635951","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:3876708eaec60862b9b8b6f73e2ae87e4abca2f228c456f973ddb7c9ee36854a"}},"version":2} \ No newline at end of file +{"entries":{".github/workflows/publish.yml":{"last_updated":"2026-11-03 09:27:04","reason":"Multi-target release archives and SHA256SUMS (subid=release-5.0.0)","source_content_hash":"sha256:930170e1eb57afbe2850a0e9c2ac179eb2b5947bf2f74d4292bcd2b0099ab8de","source_mtime_ns":"1793697915725124882","status":"🟢 Green","verification":"no_wiki"},"AGENTS.md":{"last_updated":"2026-11-05 06:26:37","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:a1fe8322f6c0f7b7fcb11ca7c510221419c9c4f15766b1ac6b1e67380c073801","source_mtime_ns":"1793859884410457800","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:32978113ded2badae40362bec72701f620e9954a1155286e7555af7d316d6888"},"CHANGELOG.md":{"last_updated":"2026-11-05 06:26:17","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:203636ef79dd12e90d7052dd7bf37960c22315a1a732568a5aeb27b7f2b9874c","source_mtime_ns":"1793859902655868900","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:757601288624e346279cef86383a88cdf7c1c467e7c6538f40c05d475e243de8"},"CLAUDE.md":{"last_updated":"2026-11-05 06:26:17","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:5200118c6eef8e19569e72d84ee275fcf797efffc12b553313f8218766c09de0","source_mtime_ns":"1793859902657869100","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:74e98420d628c198740b9aa32877dd0a20956285f22648e5d6eb5728c692456d"},"CONTRIBUTING.md":{"last_updated":"2026-11-03 05:34:35","reason":"Address the 3 Nov review findings (subid=review-2026-11-03)","source_content_hash":"sha256:d090280cd3d1c3ab1cf342d69392471ed3835512ff7381bf4409bada57bbe89c","source_mtime_ns":"1793683924316411256","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:ec0bd9342b8e9dfeefaabc8dcddeb577f6bd4f1c760d7286b21d709c2a372b29"},"Cargo.lock":{"last_updated":"2026-11-05 06:20:18","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:33ae77a3977a89f75506f16f2add899c3961d7dc276235eb9973d01bbdc9740c","source_mtime_ns":"1793859367585833600","status":"🟢 Green","verification":"no_wiki"},"Cargo.toml":{"last_updated":"2026-11-05 06:20:18","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:abdbf324522c70b251f4bb22cca3ffb05862327078a2c94ff4ba1373e87fa37a","source_mtime_ns":"1793859367584833600","status":"🟢 Green","verification":"no_wiki"},"Findings/M5-Dogfood-Assessment-Report.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:238435188b1699e5bcf4753b62a6fe55cb064413a291259f0b696b5bd3c1692f","source_mtime_ns":"1780519956000000000","status":"🟢 Green"},"Findings/M5-Dogfood-Progress.md":{"last_updated":"2026-11-03 08:06:46","reason":"Wiki marks this file as the historical M5 log (subid=protocol-v07)","source_content_hash":"sha256:ef55167e819806060dfd7dfe7cdfd4d02024ca97706a7faa243710e2630b65fe","source_mtime_ns":"1793408707259550076","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:b6b1fa4bbee0c7e8c4035cd925f6d07e1221ba483e3472878d5b88236c5cf7f9"},"Findings/M5.1-cross-hardening-analysis.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:a2c2414e5b6c9b1a802bec8734a7924850d546cd7746a8087216f3685ca36cb4","source_mtime_ns":"1780519762000000000","status":"🟢 Green"},"Findings/Milestones-Overview.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:f8b7030ec8980774cf3a2560ad7aee6537263eadf8374e650718f7c6793c6d50","source_mtime_ns":"1780800604000000000","status":"🟢 Green"},"Findings/p6_real_world_validation_report.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:0468224675888f2747674324726c0ea9a5dddded39d9a1a50f22fc3357dafc0f","source_mtime_ns":"1780520008000000000","status":"🟢 Green"},"README.md":{"last_updated":"2026-11-05 06:26:37","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:2a1a4aa3fe86c2859668b5eb6cd2d8a94d226df67e6580caa6d9e9f0b42c68f3","source_mtime_ns":"1793859902652877900","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:a50d4ce8314239a0fa5ef1d86f3f9f3337bb861473ffa2fd380bb58450ccd821"},"docs/spec.md":{"last_updated":"2026-11-03 08:00:11","reason":"Name the Rust binary and protocol v0.7 in the living principles (subid=protocol-v07)","source_content_hash":"sha256:31fe6b3b3d705628692eb0512cf44cbb21861ccfc5bb02afdd46d796ec066c6e","source_mtime_ns":"1793653008580824356","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:a58b929d25d510f15f9fe176d7823e852f6d089e398accc2e22e1ed189f260ac"},"scripts/benchmark_parity.sh":{"last_updated":"2026-11-03 08:56:15","reason":"Benchmark script and measured results.","source_content_hash":"sha256:b8f72e3245e77b9df17b303293d8cbe4a93cc36023c41b89a794b77b01daef87","status":"🟡 Yellow"},"scripts/benchmark_results.md":{"last_updated":"2026-11-03 08:56:15","reason":"Benchmark script and measured results.","source_content_hash":"sha256:8bf9342fce85f126a37f812b03b6f6997f1fe8e7c5176d30301c1a4a15aeee29","status":"🟡 Yellow"},"skills/run.md":{"last_updated":"2026-11-05 06:26:17","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:7fcc6b45009f88d76848a3c49499cec67328099e2e5a7fe1905f9e8ed14f9232","source_mtime_ns":"1793859884411457500","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:8a544f844e020c77db88bedaa7b2f05a167408c7f089521a7be5d9cfc2c233b9"},"src/api.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"MapRun\nVERSION\nMCP_TOOLS\nupdate_maps\nupdate_maps_opts\nupdate_maps_run\nseed_source_hashes\nmapped_edges\nload_dependencies\ndependency_report\nload_dependents\nlist_paths\nlist_paths_at\nsession_bootstrap\nsession_bootstrap_scoped\nsuggest_next_actions\nsuggest_next_scoped\ncheck_changes\nprepare_edit\nrecord_change\nmark_green\nhealth\nhealth_view\nread_health\nread_journal\ncache_status\nvalidate\ncycles\ncycles_view\nverify_wikis\nrecord_changes\nrecord_changes_opts\nrecord_deletion\nheal_stubs\nprune_health\nprune_health_opts\nprune_pending\nstale_wikis\nstale_wikis_in\nprune_barrels\nmetrics_snapshot\nhealing_stats\nresolution_diagnostics\nbarrel_reports\nincremental_status\nserve_once\nserve_loop\nmonitor_loop\ndaemon_ctl\ndaemon_command\ndispatch\nCLI_COMMANDS\nensure_root","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:f5575d808fab6a3334acd6af46c1f926b15156993828a21be86e7335487baab2","source_mtime_ns":"1793856867181743100","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:1959bc30bd0758cbcbef5c2c1da7bf2599b044f8f954f8d9043ca7e794590a7a"},"src/artifacts.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"HealthRow\nwrite_durable\nread_health\nwrite_health\nupsert_health_row\nJournalEntry\njournal_path\nread_journal\nparse_journal\nJournalWrite\nappend_journal\nread_pending\nfolder_card\nnew\nkeep_baseline_from","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:c5989a5fe22edf99afab4b4721fda9f45a12faff19d9f1a97277fcf1003d1ffd","source_mtime_ns":"1793856655049237400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:751e2374f151dc19c0d20ff447db2ce26b908af28067a7e74ef3a0502ce51bc2"},"src/cache.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"check_consistency\nrebuild\nConsistency\nSession\npayload_path\nby_src_path\ncommit_pending_path\nload_dependencies\nInternalEdge\nconfidence_of\nformat_edge_line\nDependencyView\nload_dependency_view\nload_internal_edges\nload_dependents\nlist_prefix\nall_paths\nFileUpdate\nupsert_file\nremove_file\nindexed_rows\nindex_by_path\nhash_if_unchanged\npayload_bytes\nstat_ns\nedges\nrel_string\nwrite_barrel_record\nprune_barrel_files\nconfidence\nacs_reason","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:d0e30e9031d1259333ebeb7799ad78c1836135fa762197d3512f7193640ed6af","source_mtime_ns":"1793856524124108400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:a48d3652a05cb7e208651c63045e714c62ba5ea1fd7e19fac3b9df84c1af31de"},"src/cache_commit.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"Consistency\nSession\ncheck_consistency\nrebuild\nopen\nknown\ndsts_of\nnote_stat\nrels\nupsert\nremove\nstage_barrel\nhas_changes\nneeds_parse\ncommit","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:fb1f90a3d27558ed141eba2d8fb408bc76a47b2c6715096dba5e75819809513f","source_mtime_ns":"1793856524408983600","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:60c2ba29a68f5feb2a5dd69b9a99d550c6d288386f2a822811eb1530742bf336"},"src/cycle_report.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:db35b610d9a9f9917805da9383e61872e66e640482f57fc9e17ae91daf77fe3d","status":"🟡 Yellow"},"src/daemon_svc.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:0887baeb3ad7f2fca851fccc0d9335dafd4b42f3e54e236175a13d39c5bcd063","status":"🟡 Yellow"},"src/jsonutil.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"Json\nparse\nparse_jsonc\nstrip_json_comments\nobj\nfrom_pairs\nget\nas_str\nas_bool\nas_array\nas_object\ninsert\nfmt","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:cb71e00e352df010928a42323d6d87bbe67348834a209348fc174b9d00489676","source_mtime_ns":"1793684429116993727","status":"🟡 Yellow","wiki_hash":"sha256:fb4cffba8b14a179dd90f201b61df2608ca78a9775e9646e7f011f1b9fa07c63"},"src/legacy_cache.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"import_if_empty","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:a127d0b1742d69b736194ca98579f5fc0611fc51a291d691aef6fe586fd68ba3","source_mtime_ns":"1793683981803718735","status":"🟡 Yellow","wiki_hash":"sha256:a6fe6c79185a46cc4b30d215475bab28f517f6e5a6fd7bce6423c2792814aac8"},"src/lib.rs":{"last_updated":"2026-11-05 06:26:16","public_symbols":"api\nartifacts\ncache\njsonutil\nmaps_out\nmcp\nmcp_groups\nparse\nscope\nsha256\nsymbols\ntext_out\ntimeutil\ncache_status\ncheck_changes\nhealth\nlist_paths\nload_dependencies\nload_dependents\nmapped_edges\nmark_green\nprepare_edit\nread_health\nread_journal\nrecord_change\nsession_bootstrap\nsuggest_next_actions\nupdate_maps\nVERSION\nJson","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:1c24582b84c5ffb3782eb2c68f4cb3694d994621b9c6d1ca416cc759a0159338","source_mtime_ns":"1793859251665208600","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:5951135711c2a9705e7351529044dec9fcb95de6f7840062faeee9d6c4e9d318"},"src/low_conf.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:3ade5fc70ce585a48b9acf6a2b48753e58e80f63281a31c8b8453816700b375e","status":"🟡 Yellow"},"src/main.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:2b3cebdafca3ca3da7831101a63b36f72260b3b2879871e5364b427428e782e0","source_mtime_ns":"1793683990351610198","status":"🟡 Yellow","wiki_hash":"sha256:db6e1cd5beeb90e5a65b3e00a37ee2c73ea4c53750771151e655459a1b823ff5"},"src/maps_out.rs":{"last_updated":"2026-11-05 05:15:33","public_symbols":"current\nwrite\nwrite_status\nread_status","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:4223756e3ddd7a7317d364f5de9bbffe1fe59e820b0b8187164bd30449039432","source_mtime_ns":"1793854043821084000","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:5218571835e011f1f33b83b5a57723204910bb8209a5f88a1a2d3a06ee82e30a"},"src/mcp.rs":{"last_updated":"2026-11-05 06:26:16","public_symbols":"GroupState\nLIST_CHANGED\nactive\ngroups_state\nconfigure\nrefresh\ntool_schema\nhandle_message\nserve_stdio\ninstructions","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:86e934f010854b378356746f7c22026f34bf3448a15fddd010d7ffcf9c29d4e3","source_mtime_ns":"1793859786351065300","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:6bbb0766ec896835b385a13b6d83d9be30de70652ad12c6b3c2a00c230616e54"},"src/mcp_groups.rs":{"last_updated":"2026-11-05 06:26:16","public_symbols":"TOOLS_VAR\nDISABLE_VAR\nGROUPS\ngroup_of\nSource\nSelection\nAgentTools\nall\nfrom_env\nparse\nresolve\nis_filtered\nallows\nenabled\nrefusal\nactive_groups\nsummary","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:c85c6f1995109fc3c10556058463cc5e73e37204cc7da9999140d26f1cb445ce","source_mtime_ns":"1793859786781809400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:b621998ab1e53122af6eedfaa18f9772c93d2681d0158a6add8f4661ef5540f1"},"src/parse.rs":{"last_updated":"2026-11-05 05:15:33","public_symbols":"RawImport\nKind\nScan\nlanguage\nread_utf8\nscan_file_warned\nscan_file\nresolve_project\nrust_public_symbols\nresolve_python_spec\nFactEdge\nFileFacts\nAnalysis\nanalyze_files\nanalyze_changed\nedges_for_files","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:4122cf1ec797e2af0a410dcf13d6cfb3f087410db5dcae27cff7c79cbdd88228","source_mtime_ns":"1793855453252350400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:3ea6562f6fbb69c3510cba443a994caa2dbab3fae30e290847ec1cd43913e047"},"src/pending_line.rs":{"last_updated":"2026-11-05 05:19:31","public_symbols":"file_of\nformat_item\nEMPTY_NOTE\nappend_item\nremove_item\nrecord_message\nCHECK_MESSAGE","reason":"wiki (claude/windows-verify pending)","source_content_hash":"sha256:f1ad66b1c330ce490b36a72d58cb2a341b0f44b0b5ec2166cd943a83cf694d05","source_mtime_ns":"1793855871596115600","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:3bac5aead2f3a0b020e056fe388d7670f9a3b45d79be75d197f5b71966620f56"},"src/proc.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:8f13798a8b9289d78913becc626056c8b016838570e356e09bfa3333e800351c","status":"🟡 Yellow"},"src/project_lock.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"ProjectLock\ndrop\nacquire","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:194e329f35ff59b11fc734b980a1ee33f8e464bcdb5eae899486e487daef3a25","source_mtime_ns":"1793678007370625780","status":"🟡 Yellow","wiki_hash":"sha256:fccc8d547f30262ff64d506d842472623e828ebe39fde71532a683c6956329d2"},"src/scope.rs":{"last_updated":"2026-11-05 05:15:34","public_symbols":"SOURCE_EXTS\nScope\ndetect\nread_path_list\nexcludes\nis_source\ncollect\nrel_of\ndefault_map_roots\nrel_arg\nallows_walk","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:0843deef3d82162edf7bac2c53c9a9f716735b4e639451f7fb36620de2dcd059","source_mtime_ns":"1793854073257790700","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:574d4cc8bd261700b1e192628435926d8f1e533f7f1967e27eb6c797e59e6c0e"},"src/sha256.rs":{"last_updated":"2026-11-05 04:14:08","public_symbols":"sha256\nsha256_hex\nsha256_prefixed\ncontent_sha256_prefixed\nfile_sha256_prefixed","reason":"wiki updated (claude/windows-verify)","source_content_hash":"sha256:2f4f8a8ccb9f9d4748fc0678e6bac63dc69ade57e9ab4b3c6eb2a1c43fcf5c14","source_mtime_ns":"1793851995838527400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:0d1d67e61bed7a20c6a8413a352a55fb87f05bda6e39760015727d128a67ae33"},"src/symbols.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:4a150ba04e9ea26020c874c5e256a9ec5acc3ef4d621fb6ff03b21935c3f8046","status":"🟡 Yellow"},"src/text_out.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:8e0edc1141a2c1745c0e6fdd7a7645c7332365fac532d52fb3e188f4ef06148e","status":"🟡 Yellow"},"src/timeutil.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:9921127144d9d40619e260753e700e9c8a47135ed95b2ad8791afb7fe78afd75","status":"🟡 Yellow"},"src/wiki_files.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:2612539ce9092a3d126d80ce2947f6b4555ddb0bb335769b1619ec67d08a5e84","status":"🟡 Yellow"},"tests/agent_args.rs":{"last_updated":"2026-11-05 04:14:08","reason":"new: agent-style file args, missing args, lean MCP outputs, init roots, CRLF (claude/windows-verify)","source_content_hash":"sha256:ae25dcc233b1d40c48dbc7199e350032717412316089084751b9280970feb66d","status":"🟡 Yellow"},"tests/behaviour_gaps.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:8c8d669dae2dbe39b88c2223d20fb2fca51ac1605c62edd108d6ef224223402b","source_mtime_ns":"1793684893298602299","status":"🟡 Yellow","wiki_hash":"sha256:b9d20a310ca48ffd858e6d0d4e49b5e0568ecb57dc5ad981eb54398562864691"},"tests/cache_and_artifacts.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:b9483666c1e19f90d4db1af718b08beebadfbcba66152497b7694d8e757a5ec1","status":"🟡 Yellow"},"tests/cli_surface.rs":{"last_updated":"2026-11-05 05:37:11","reason":"docs name the Cargo version (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:0aef6e3256a524e014971637bad8a928deba528b734995728bfb72ea606730f5","status":"🟡 Yellow"},"tests/contract_gaps.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:dc91a239bbc615524b4ac2c58d06515183dfc4981309906003f551e6721d82ae","status":"🟡 Yellow"},"tests/dogfood.rs":{"last_updated":"2026-11-05 06:20:17","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:36af6c04119986796434bcf75be9095cd2c28d7e0df476c72463343181c83328","source_mtime_ns":"1793859367674990400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:0bc5f3d78d1779ba6302ecc406dc0b25d8beda25f1681a26d57e97210df19906"},"tests/parity.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:0246038a1cc01bf66da2fd186ede61f2dcd2c98da9c0c90dd7f3b2cbab1036db","source_mtime_ns":"1793683314773282057","status":"🟡 Yellow","wiki_hash":"sha256:32753c244642df6e08f8578c6203f77225363783c15bc57c33a84f03989f2378"},"tests/parity_fixes.rs":{"last_updated":"2026-11-05 05:15:33","reason":"pending item wording and empty-queue note (claude/windows-verify speed)","source_content_hash":"sha256:b74f37dffb2a5bbcc8724298885a677a9d4476f846791d31770798e0a6caa7a3","status":"🟡 Yellow"},"tests/protocol_v07.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:bb7cffecabc3fb51ebcc77c64f7fd78f5cd15c445d7e13493ed491227280f37d","source_mtime_ns":"1793684781738827745","status":"🟡 Yellow","wiki_hash":"sha256:b38f4a13e316cefd56070f822980b4f83d9cdacb850ab1978de48ed35c630ec8"},"tests/robustness.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:fad304193a47baa8cce21cff8786b35974c7c7f6f71b3318edeb68bd60121681","status":"🟡 Yellow"},"tests/skip_maps.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:2eed0c6bc97d91a4be3f2b6ab08c78c62a3a05725a503496e3df91abad6b2130","status":"🟡 Yellow"},"tests/speed_paths.rs":{"last_updated":"2026-11-05 05:37:11","reason":"self-heal and durable user-state tests (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:a9348e032c3ffd9f6960710b364470cbcbf935f366af604dd2ad62ac4f2a7a9e","status":"🟡 Yellow"},"tests/tool_groups.rs":{"last_updated":"2026-11-05 06:26:16","reason":"agent-chosen tool groups from the AGENTS.md agent-tools block, list_changed on edits (claude/tool-groups)","source_content_hash":"sha256:892fbc4330f902ac0fb01b8d8ea5c8c018ca7422408ea759853a8b3d8cf711c6","status":"🟡 Yellow"},"wikifier.sh":{"last_updated":"2026-11-03 08:06:46","reason":"Wiki describes the Rust binary launcher (subid=protocol-v07)","source_content_hash":"sha256:4f467e2117e8c361882054998cb0506717d9555e2aa570f0e176fc18d9c2f4aa","source_mtime_ns":"1793410024331635951","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:3876708eaec60862b9b8b6f73e2ae87e4abca2f228c456f973ddb7c9ee36854a"}},"version":2} \ No newline at end of file diff --git a/file_health.md b/file_health.md index 0f2c0c1..0d02009 100644 --- a/file_health.md +++ b/file_health.md @@ -3,22 +3,22 @@ | File | Status | Last Updated | Reason / Intent | |------|--------|--------------|-----------------| | .github/workflows/publish.yml | 🟢 Green | 2026-11-03 09:27:04 | Multi-target release archives and SHA256SUMS (subid=release-5.0.0) | -| AGENTS.md | 🟢 Green | 2026-11-05 05:37:13 | wiki updated (claude/windows-verify release-5.1.0) | -| CHANGELOG.md | 🟢 Green | 2026-11-05 05:37:12 | wiki updated (claude/windows-verify release-5.1.0) | -| CLAUDE.md | 🟢 Green | 2026-11-05 05:37:13 | wiki updated (claude/windows-verify release-5.1.0) | +| AGENTS.md | 🟢 Green | 2026-11-05 06:26:37 | wiki updated (claude/tool-groups) | +| CHANGELOG.md | 🟢 Green | 2026-11-05 06:26:17 | wiki updated (claude/tool-groups) | +| CLAUDE.md | 🟢 Green | 2026-11-05 06:26:17 | wiki updated (claude/tool-groups) | | CONTRIBUTING.md | 🟢 Green | 2026-11-03 05:34:35 | Address the 3 Nov review findings (subid=review-2026-11-03) | -| Cargo.lock | 🟢 Green | 2026-11-05 05:37:21 | version 5.1.0 (claude/windows-verify release-5.1.0) | -| Cargo.toml | 🟢 Green | 2026-11-05 05:37:20 | version 5.1.0 (claude/windows-verify release-5.1.0) | +| Cargo.lock | 🟢 Green | 2026-11-05 06:20:18 | wiki updated (claude/tool-groups) | +| Cargo.toml | 🟢 Green | 2026-11-05 06:20:18 | wiki updated (claude/tool-groups) | | Findings/M5-Dogfood-Assessment-Report.md | 🟢 Green | 2026-07-09 05:02:27 | kept; stale yellow cleared | | Findings/M5-Dogfood-Progress.md | 🟢 Green | 2026-11-03 08:06:46 | Wiki marks this file as the historical M5 log (subid=protocol-v07) | | Findings/M5.1-cross-hardening-analysis.md | 🟢 Green | 2026-07-09 05:02:27 | kept; stale yellow cleared | | Findings/Milestones-Overview.md | 🟢 Green | 2026-07-09 05:02:27 | kept; stale yellow cleared | | Findings/p6_real_world_validation_report.md | 🟢 Green | 2026-07-09 05:02:27 | kept; stale yellow cleared | -| README.md | 🟢 Green | 2026-11-05 05:37:12 | wiki updated (claude/windows-verify release-5.1.0) | +| README.md | 🟢 Green | 2026-11-05 06:26:37 | wiki updated (claude/tool-groups) | | docs/spec.md | 🟢 Green | 2026-11-03 08:00:11 | Name the Rust binary and protocol v0.7 in the living principles (subid=protocol-v07) | | scripts/benchmark_parity.sh | 🟡 Yellow | 2026-11-03 08:56:15 | Benchmark script and measured results. | | scripts/benchmark_results.md | 🟡 Yellow | 2026-11-03 08:56:15 | Benchmark script and measured results. | -| skills/run.md | 🟢 Green | 2026-11-05 05:37:13 | wiki updated (claude/windows-verify release-5.1.0) | +| skills/run.md | 🟢 Green | 2026-11-05 06:26:17 | wiki updated (claude/tool-groups) | | src/api.rs | 🟢 Green | 2026-11-05 05:37:12 | wiki updated (claude/windows-verify release-5.1.0) | | src/artifacts.rs | 🟢 Green | 2026-11-05 05:37:12 | wiki updated (claude/windows-verify release-5.1.0) | | src/cache.rs | 🟢 Green | 2026-11-05 05:37:12 | wiki updated (claude/windows-verify release-5.1.0) | @@ -27,11 +27,12 @@ | src/daemon_svc.rs | 🟡 Yellow | 2026-11-03 08:56:15 | Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. | | src/jsonutil.rs | 🟡 Yellow | 2026-11-03 08:56:14 | Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. | | src/legacy_cache.rs | 🟡 Yellow | 2026-11-03 08:56:14 | Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. | -| src/lib.rs | 🟡 Yellow | 2026-11-03 08:56:14 | Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. | +| src/lib.rs | 🟢 Green | 2026-11-05 06:26:16 | wiki updated (claude/tool-groups) | | src/low_conf.rs | 🟡 Yellow | 2026-11-03 08:56:15 | Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. | | src/main.rs | 🟡 Yellow | 2026-11-03 08:56:14 | Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. | | src/maps_out.rs | 🟢 Green | 2026-11-05 05:15:33 | wiki updated (claude/windows-verify speed) | -| src/mcp.rs | 🟢 Green | 2026-11-05 05:15:47 | wiki updated (claude/windows-verify speed) | +| src/mcp.rs | 🟢 Green | 2026-11-05 06:26:16 | wiki updated (claude/tool-groups) | +| src/mcp_groups.rs | 🟢 Green | 2026-11-05 06:26:16 | wiki updated (claude/tool-groups) | | src/parse.rs | 🟢 Green | 2026-11-05 05:15:33 | wiki updated (claude/windows-verify speed) | | src/pending_line.rs | 🟢 Green | 2026-11-05 05:19:31 | wiki (claude/windows-verify pending) | | src/proc.rs | 🟡 Yellow | 2026-11-03 08:56:14 | Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. | @@ -47,11 +48,12 @@ | tests/cache_and_artifacts.rs | 🟡 Yellow | 2026-11-03 08:56:14 | Tests for those parity fixes. | | tests/cli_surface.rs | 🟡 Yellow | 2026-11-05 05:37:11 | docs name the Cargo version (claude/windows-verify release-5.1.0) | | tests/contract_gaps.rs | 🟡 Yellow | 2026-11-03 08:56:14 | Tests for those parity fixes. | -| tests/dogfood.rs | 🟢 Green | 2026-11-05 05:15:34 | wiki updated (claude/windows-verify speed) | +| tests/dogfood.rs | 🟢 Green | 2026-11-05 06:20:17 | wiki updated (claude/tool-groups) | | tests/parity.rs | 🟡 Yellow | 2026-11-03 08:56:15 | Tests for those parity fixes. | | tests/parity_fixes.rs | 🟡 Yellow | 2026-11-05 05:15:33 | pending item wording and empty-queue note (claude/windows-verify speed) | | tests/protocol_v07.rs | 🟡 Yellow | 2026-11-03 08:56:15 | Tests for those parity fixes. | | tests/robustness.rs | 🟡 Yellow | 2026-11-03 08:56:15 | Tests for those parity fixes. | | tests/skip_maps.rs | 🟡 Yellow | 2026-11-03 08:56:15 | Tests for those parity fixes. | | tests/speed_paths.rs | 🟡 Yellow | 2026-11-05 05:37:11 | self-heal and durable user-state tests (claude/windows-verify release-5.1.0) | +| tests/tool_groups.rs | 🟡 Yellow | 2026-11-05 06:26:16 | agent-chosen tool groups from the AGENTS.md agent-tools block, list_changed on edits (claude/tool-groups) | | wikifier.sh | 🟢 Green | 2026-11-03 08:06:46 | Wiki describes the Rust binary launcher (subid=protocol-v07) | diff --git a/journal/2026/11/05.md b/journal/2026/11/05.md index 7634120..0e63710 100644 --- a/journal/2026/11/05.md +++ b/journal/2026/11/05.md @@ -270,3 +270,159 @@ **File:** Cargo.lock **Reason:** version 5.1.0 (claude/windows-verify release-5.1.0) +## [2026-11-05 06:20:15] check-changes +**File:** AGENTS.md +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:20:15] check-changes +**File:** CHANGELOG.md +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:20:15] check-changes +**File:** CLAUDE.md +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:20:15] check-changes +**File:** Cargo.lock +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:20:15] check-changes +**File:** Cargo.toml +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:20:15] check-changes +**File:** README.md +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:20:15] check-changes +**File:** skills/run.md +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:20:16] check-changes +**File:** src/lib.rs +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:20:16] check-changes +**File:** src/mcp.rs +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:20:16] check-changes +**File:** tests/dogfood.rs +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:20:16] record-change +**File:** src/mcp.rs +**Reason:** MCP tool groups with WIKIFIER_TOOLS/WIKIFIER_DISABLE per the suite convention (claude/tool-groups) + +## [2026-11-05 06:20:16] record-change +**File:** src/mcp_groups.rs +**Reason:** MCP tool groups with WIKIFIER_TOOLS/WIKIFIER_DISABLE per the suite convention (claude/tool-groups) + +## [2026-11-05 06:20:16] record-change +**File:** src/lib.rs +**Reason:** MCP tool groups with WIKIFIER_TOOLS/WIKIFIER_DISABLE per the suite convention (claude/tool-groups) + +## [2026-11-05 06:20:16] record-change +**File:** tests/tool_groups.rs +**Reason:** MCP tool groups with WIKIFIER_TOOLS/WIKIFIER_DISABLE per the suite convention (claude/tool-groups) + +## [2026-11-05 06:20:16] record-change +**File:** tests/dogfood.rs +**Reason:** MCP tool groups with WIKIFIER_TOOLS/WIKIFIER_DISABLE per the suite convention (claude/tool-groups) + +## [2026-11-05 06:20:16] record-change +**File:** README.md +**Reason:** release 5.2.0: tool groups docs and version (claude/tool-groups) + +## [2026-11-05 06:20:16] record-change +**File:** CHANGELOG.md +**Reason:** release 5.2.0: tool groups docs and version (claude/tool-groups) + +## [2026-11-05 06:20:16] record-change +**File:** skills/run.md +**Reason:** release 5.2.0: tool groups docs and version (claude/tool-groups) + +## [2026-11-05 06:20:17] record-change +**File:** AGENTS.md +**Reason:** release 5.2.0: tool groups docs and version (claude/tool-groups) + +## [2026-11-05 06:20:17] record-change +**File:** CLAUDE.md +**Reason:** release 5.2.0: tool groups docs and version (claude/tool-groups) + +## [2026-11-05 06:20:17] record-change +**File:** Cargo.toml +**Reason:** release 5.2.0: tool groups docs and version (claude/tool-groups) + +## [2026-11-05 06:20:17] record-change +**File:** Cargo.lock +**Reason:** release 5.2.0: tool groups docs and version (claude/tool-groups) + +## [2026-11-05 06:26:16] check-changes +**File:** AGENTS.md +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:26:16] check-changes +**File:** CHANGELOG.md +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:26:16] check-changes +**File:** CLAUDE.md +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:26:16] check-changes +**File:** README.md +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:26:16] check-changes +**File:** skills/run.md +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:26:16] check-changes +**File:** src/mcp.rs +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:26:16] check-changes +**File:** src/mcp_groups.rs +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:26:16] check-changes +**File:** tests/tool_groups.rs +**Reason:** content changed since last mark-green (check-changes) + +## [2026-11-05 06:26:16] record-change +**File:** src/mcp.rs +**Reason:** agent-chosen tool groups from the AGENTS.md agent-tools block, list_changed on edits (claude/tool-groups) + +## [2026-11-05 06:26:16] record-change +**File:** src/mcp_groups.rs +**Reason:** agent-chosen tool groups from the AGENTS.md agent-tools block, list_changed on edits (claude/tool-groups) + +## [2026-11-05 06:26:16] record-change +**File:** src/lib.rs +**Reason:** agent-chosen tool groups from the AGENTS.md agent-tools block, list_changed on edits (claude/tool-groups) + +## [2026-11-05 06:26:16] record-change +**File:** tests/tool_groups.rs +**Reason:** agent-chosen tool groups from the AGENTS.md agent-tools block, list_changed on edits (claude/tool-groups) + +## [2026-11-05 06:26:16] record-change +**File:** README.md +**Reason:** Choosing groups section; AGENTS.md agent-tools block (claude/tool-groups) + +## [2026-11-05 06:26:16] record-change +**File:** CHANGELOG.md +**Reason:** Choosing groups section; AGENTS.md agent-tools block (claude/tool-groups) + +## [2026-11-05 06:26:16] record-change +**File:** skills/run.md +**Reason:** Choosing groups section; AGENTS.md agent-tools block (claude/tool-groups) + +## [2026-11-05 06:26:16] record-change +**File:** AGENTS.md +**Reason:** Choosing groups section; AGENTS.md agent-tools block (claude/tool-groups) + +## [2026-11-05 06:26:16] record-change +**File:** CLAUDE.md +**Reason:** Choosing groups section; AGENTS.md agent-tools block (claude/tool-groups) + diff --git a/library.md b/library.md index c02c907..0b5151e 100644 --- a/library.md +++ b/library.md @@ -2,7 +2,7 @@ Generated by `wikifier update-maps`. Agents orient with the root folder card and `list-paths`, not this mermaid. -Files: 35. Edges: 108. +Files: 37. Edges: 115. ## File Tree @@ -20,6 +20,7 @@ src/low_conf.rs src/main.rs src/maps_out.rs src/mcp.rs +src/mcp_groups.rs src/parse.rs src/pending_line.rs src/proc.rs @@ -42,6 +43,7 @@ tests/protocol_v07.rs tests/robustness.rs tests/skip_maps.rs tests/speed_paths.rs +tests/tool_groups.rs ``` ## Dependencies @@ -92,6 +94,7 @@ flowchart LR n19["src/lib.rs"] --> n7["src/low_conf.rs"] n19["src/lib.rs"] --> n8["src/maps_out.rs"] n19["src/lib.rs"] --> n20["src/mcp.rs"] + n19["src/lib.rs"] --> n21["src/mcp_groups.rs"] n19["src/lib.rs"] --> n9["src/parse.rs"] n19["src/lib.rs"] --> n10["src/pending_line.rs"] n19["src/lib.rs"] --> n11["src/proc.rs"] @@ -99,38 +102,37 @@ flowchart LR n19["src/lib.rs"] --> n13["src/scope.rs"] n19["src/lib.rs"] --> n14["src/sha256.rs"] n19["src/lib.rs"] --> n15["src/symbols.rs"] - n19["src/lib.rs"] --> n21["src/text_out.rs"] + n19["src/lib.rs"] --> n22["src/text_out.rs"] n19["src/lib.rs"] --> n16["src/timeutil.rs"] n19["src/lib.rs"] --> n17["src/wiki_files.rs"] n7["src/low_conf.rs"] --> n2["src/cache.rs"] - n22["src/main.rs"] --> n0["src/api.rs"] - n22["src/main.rs"] --> n5["src/jsonutil.rs"] - n22["src/main.rs"] --> n20["src/mcp.rs"] - n22["src/main.rs"] --> n21["src/text_out.rs"] - n22["src/main.rs"] --> n16["src/timeutil.rs"] + n23["src/main.rs"] --> n0["src/api.rs"] + n23["src/main.rs"] --> n5["src/jsonutil.rs"] + n23["src/main.rs"] --> n20["src/mcp.rs"] + n23["src/main.rs"] --> n22["src/text_out.rs"] + n23["src/main.rs"] --> n16["src/timeutil.rs"] n8["src/maps_out.rs"] --> n2["src/cache.rs"] n8["src/maps_out.rs"] --> n5["src/jsonutil.rs"] n20["src/mcp.rs"] --> n0["src/api.rs"] n20["src/mcp.rs"] --> n5["src/jsonutil.rs"] - n20["src/mcp.rs"] --> n21["src/text_out.rs"] + n20["src/mcp.rs"] --> n21["src/mcp_groups.rs"] + n20["src/mcp.rs"] --> n22["src/text_out.rs"] + n21["src/mcp_groups.rs"] --> n0["src/api.rs"] n9["src/parse.rs"] --> n5["src/jsonutil.rs"] n9["src/parse.rs"] --> n13["src/scope.rs"] n12["src/project_lock.rs"] --> n11["src/proc.rs"] - n21["src/text_out.rs"] --> n5["src/jsonutil.rs"] - n23["tests/agent_args.rs"] --> n0["src/api.rs"] - n23["tests/agent_args.rs"] --> n19["src/lib.rs"] - n23["tests/agent_args.rs"] --> n20["src/mcp.rs"] - n24["tests/behaviour_gaps.rs"] --> n2["src/cache.rs"] - n24["tests/behaviour_gaps.rs"] --> n5["src/jsonutil.rs"] - n24["tests/behaviour_gaps.rs"] --> n19["src/lib.rs"] - n24["tests/behaviour_gaps.rs"] --> n20["src/mcp.rs"] - n25["tests/cache_and_artifacts.rs"] --> n2["src/cache.rs"] - n25["tests/cache_and_artifacts.rs"] --> n19["src/lib.rs"] - n26["tests/cli_surface.rs"] --> n0["src/api.rs"] - n26["tests/cli_surface.rs"] --> n5["src/jsonutil.rs"] + n22["src/text_out.rs"] --> n5["src/jsonutil.rs"] + n24["tests/agent_args.rs"] --> n0["src/api.rs"] + n24["tests/agent_args.rs"] --> n19["src/lib.rs"] + n24["tests/agent_args.rs"] --> n20["src/mcp.rs"] + n25["tests/behaviour_gaps.rs"] --> n2["src/cache.rs"] + n25["tests/behaviour_gaps.rs"] --> n5["src/jsonutil.rs"] + n25["tests/behaviour_gaps.rs"] --> n19["src/lib.rs"] + n25["tests/behaviour_gaps.rs"] --> n20["src/mcp.rs"] + n26["tests/cache_and_artifacts.rs"] --> n2["src/cache.rs"] ``` -Mermaid shows the first 80 edges of 108. +Mermaid shows the first 80 edges of 115. | Source | Depends on | |--------|------------| @@ -141,11 +143,12 @@ Mermaid shows the first 80 edges of 108. | src/cycle_report.rs | src/jsonutil.rs | | src/daemon_svc.rs | src/jsonutil.rs, src/timeutil.rs | | src/legacy_cache.rs | src/cache.rs, src/jsonutil.rs, src/maps_out.rs, src/project_lock.rs | -| src/lib.rs | src/api.rs, src/artifacts.rs, src/cache.rs, src/cache_commit.rs, src/cycle_report.rs, src/daemon_svc.rs, src/jsonutil.rs, src/legacy_cache.rs, src/low_conf.rs, src/maps_out.rs, src/mcp.rs, src/parse.rs, src/pending_line.rs, src/proc.rs, src/project_lock.rs, src/scope.rs, src/sha256.rs, src/symbols.rs, src/text_out.rs, src/timeutil.rs, src/wiki_files.rs | +| src/lib.rs | src/api.rs, src/artifacts.rs, src/cache.rs, src/cache_commit.rs, src/cycle_report.rs, src/daemon_svc.rs, src/jsonutil.rs, src/legacy_cache.rs, src/low_conf.rs, src/maps_out.rs, src/mcp.rs, src/mcp_groups.rs, src/parse.rs, src/pending_line.rs, src/proc.rs, src/project_lock.rs, src/scope.rs, src/sha256.rs, src/symbols.rs, src/text_out.rs, src/timeutil.rs, src/wiki_files.rs | | src/low_conf.rs | src/cache.rs | | src/main.rs | src/api.rs, src/jsonutil.rs, src/mcp.rs, src/text_out.rs, src/timeutil.rs | | src/maps_out.rs | src/cache.rs, src/jsonutil.rs | -| src/mcp.rs | src/api.rs, src/jsonutil.rs, src/text_out.rs | +| src/mcp.rs | src/api.rs, src/jsonutil.rs, src/mcp_groups.rs, src/text_out.rs | +| src/mcp_groups.rs | src/api.rs | | src/parse.rs | src/jsonutil.rs, src/scope.rs | | src/project_lock.rs | src/proc.rs | | src/text_out.rs | src/jsonutil.rs | @@ -161,6 +164,7 @@ Mermaid shows the first 80 edges of 108. | tests/robustness.rs | src/api.rs, src/cache.rs, src/jsonutil.rs, src/lib.rs | | tests/skip_maps.rs | src/api.rs, src/cache.rs, src/jsonutil.rs, src/lib.rs | | tests/speed_paths.rs | src/api.rs, src/artifacts.rs, src/cache.rs, src/lib.rs, src/mcp.rs, src/sha256.rs | +| tests/tool_groups.rs | src/api.rs, src/jsonutil.rs, src/mcp.rs, src/mcp_groups.rs | Edges with a conditional, dynamic, barrel, or lower-confidence flag: 0. Run `wikifier cycles` for a break hint on each strongly connected component. diff --git a/pending_updates.md b/pending_updates.md index a1570ae..8e67ede 100644 --- a/pending_updates.md +++ b/pending_updates.md @@ -2,7 +2,6 @@ - src/jsonutil.rs: LLM/agent edit — Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. - src/legacy_cache.rs: LLM/agent edit — Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. -- src/lib.rs: LLM/agent edit — Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. - src/main.rs: LLM/agent edit — Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. - src/proc.rs: LLM/agent edit — Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. - src/project_lock.rs: LLM/agent edit — Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. @@ -26,3 +25,4 @@ - tests/parity_fixes.rs: LLM/agent edit — Tests for those parity fixes. - tests/agent_args.rs: LLM/agent edit — new: agent-style file args, missing args, lean MCP outputs, init roots, CRLF (claude/windows-verify) - tests/speed_paths.rs: new: fast paths give the slow paths' answers (claude/windows-verify speed) — refresh the wiki, then mark-green +- tests/tool_groups.rs: MCP tool groups with WIKIFIER_TOOLS/WIKIFIER_DISABLE per the suite convention (claude/tool-groups) — refresh the wiki, then mark-green From 2bd4bf9f8bae0f3df46ce451fcfc15dda3dd433a Mon Sep 17 00:00:00 2001 From: IronAdamant <18153828+IronAdamant@users.noreply.github.com> Date: Thu, 5 Nov 2026 17:30:11 +1100 Subject: [PATCH 4/5] Always advertise tools.listChanged; nested agent-tools examples are text. Per the updated convention, initialize advertises capabilities.tools.listChanged: true on every server, so an agent can add an agent-tools block mid-session and the client refetches the list without a restart. It is the only field of the default initialize reply that differs from 5.1.0; the golden test now applies just that change. An agent-tools block inside another fenced block (a docs example) was already read as text; a new test pins it for this repository, which dogfoods its own server: the "Choosing groups" examples in AGENTS.md switch nothing and the repo keeps all 31 tools. The test helper no longer unwraps writes to a server that already exited 2, which failed with a broken pipe on Linux CI. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CMYkogM3QWVjMLzWKGyjuJ --- CHANGELOG.md | 4 +-- README.md | 2 +- src/mcp.rs | 14 ++++------ src/mcp.rs.wiki.md | 2 +- src/mcp_groups.rs | 3 ++- tests/tool_groups.rs | 62 ++++++++++++++++++++++++++++++-------------- 6 files changed, 54 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f6546c..7e0e18a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [5.2.0] - 2026-11-05 ### Added -- MCP tool groups, following the suite-wide convention. Every tool is in one of six groups: `core` (always on), `notes`, `health`, `map`, `cycles`, `status`. `WIKIFIER_TOOLS` (allowlist) and `WIKIFIER_DISABLE` (applied after it) take group or tool names, ignore case and spaces, and `WIKIFIER_TOOLS` accepts `all`. Switched-off tools are absent from `tools/list`; calling one returns `isError` with `tool "" is disabled (group "") by ; …`. An unknown name, or `core` or one of its tools in `WIKIFIER_DISABLE`, prints one line to stderr and exits 2. An empty or whitespace-only value counts as unset. When either variable is set, `initialize` carries an `instructions` line naming the active groups and `list_core_tools` adds a `groups` line and lists only the exposed tools. With neither set, every MCP reply is byte-identical to 5.1.0. The CLI ignores both variables. -- Agents choose the groups per project: the first fenced `agent-tools` block in AGENTS.md at the server's project root (`WIKIFIER_PROJECT_ROOT`, else the working directory) may hold `wikifier: tools ` and `wikifier: disable ` lines (commas or spaces, `#` comments, other tools' lines ignored). `WIKIFIER_TOOLS` overrides the `tools` line and `WIKIFIER_DISABLE` the `disable` line. A mistake in the block (unknown name, `core` in `disable`, unknown key) never stops the server: that line is ignored and a warning line goes into the `initialize` instructions and `list_core_tools`. The server stats AGENTS.md (mtime and size) before every request; when the exposed tool list changes it sends `notifications/tools/list_changed` before the response. With a block or a switch present, `initialize` advertises `tools.listChanged` and its instructions end with the groups line. With neither, replies are byte-identical to 5.1.0, so a client only learns about `listChanged` once a block exists at startup. +- MCP tool groups, following the suite-wide convention. Every tool is in one of six groups: `core` (always on), `notes`, `health`, `map`, `cycles`, `status`. `WIKIFIER_TOOLS` (allowlist) and `WIKIFIER_DISABLE` (applied after it) take group or tool names, ignore case and spaces, and `WIKIFIER_TOOLS` accepts `all`. Switched-off tools are absent from `tools/list`; calling one returns `isError` with `tool "" is disabled (group "") by ; …`. An unknown name, or `core` or one of its tools in `WIKIFIER_DISABLE`, prints one line to stderr and exits 2. An empty or whitespace-only value counts as unset. When either variable is set, `initialize` carries an `instructions` line naming the active groups and `list_core_tools` adds a `groups` line and lists only the exposed tools. With neither set, `tools/list` and every other reply are byte-identical to 5.1.0, except that `initialize` now always advertises `capabilities.tools.listChanged: true`. The CLI ignores both variables. +- Agents choose the groups per project: the first fenced `agent-tools` block in AGENTS.md at the server's project root (`WIKIFIER_PROJECT_ROOT`, else the working directory) may hold `wikifier: tools ` and `wikifier: disable ` lines (commas or spaces, `#` comments, other tools' lines ignored). `WIKIFIER_TOOLS` overrides the `tools` line and `WIKIFIER_DISABLE` the `disable` line. A mistake in the block (unknown name, `core` in `disable`, unknown key) never stops the server: that line is ignored and a warning line goes into the `initialize` instructions and `list_core_tools`. The server stats AGENTS.md (mtime and size) before every request; when the exposed tool list changes it sends `notifications/tools/list_changed` before the response. `initialize` always advertises `tools.listChanged`, so a block added mid-session takes effect without a restart. With a block or a switch present, its instructions end with the groups line. An `agent-tools` block inside another fenced block (a docs example) is text, not config. - "Choosing groups" sections in AGENTS.md, README, and `skills/run.md`: what each group is for, when to turn it off, and the line to add. This repository's own AGENTS.md has no block, so dogfooding keeps every tool. - `tools/list` sizes: 22.7 KB (31 tools) with every group on; 18.2 KB without `notes`, 17.0 KB without `health`, 20.8 KB without `map`, 21.9 KB without `cycles`, 19.4 KB without `status`; 16.8 KB (22 tools) with the recommended `WIKIFIER_DISABLE=map,cycles,status`; 6.6 KB (8 tools) with `WIKIFIER_TOOLS=core`. diff --git a/README.md b/README.md index 5964446..084d942 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Every tool takes `project_root` (an absolute path). Without it the server uses ` ### Tool groups -The 31 MCP tools are in six groups. The agent picks the groups a project needs with one line in the project's AGENTS.md (see Choosing groups below); an operator can override that in the MCP client's `env` block. The CLI is not affected. `WIKIFIER_TOOLS` is an allowlist and `WIKIFIER_DISABLE` hides groups or single tools after it; both take comma-separated group or tool names, ignore case and spaces, and `WIKIFIER_TOOLS` also accepts `all`. With neither set, the listing is exactly what it was. An unknown name, or `core` or one of its tools in `WIKIFIER_DISABLE`, stops the server with exit code 2 and a one-line message, so a mistake shows up as a failed server. An empty value counts as unset. A switched-off tool, if called, returns `isError` naming the switch to change. +The 31 MCP tools are in six groups. The agent picks the groups a project needs with one line in the project's AGENTS.md (see Choosing groups below); an operator can override that in the MCP client's `env` block. The CLI is not affected. `WIKIFIER_TOOLS` is an allowlist and `WIKIFIER_DISABLE` hides groups or single tools after it; both take comma-separated group or tool names, ignore case and spaces, and `WIKIFIER_TOOLS` also accepts `all`. With neither set, the listing is exactly what it was; `initialize` always advertises `tools.listChanged`, so an edit to the AGENTS.md block takes effect without a restart. A block inside another fenced block (a docs example) is ignored. An unknown name, or `core` or one of its tools in `WIKIFIER_DISABLE`, stops the server with exit code 2 and a one-line message, so a mistake shows up as a failed server. An empty value counts as unset. A switched-off tool, if called, returns `isError` naming the switch to change. | Group | Tools | Overlaps with | |---|---|---| diff --git a/src/mcp.rs b/src/mcp.rs index d53fd07..15f5295 100644 --- a/src/mcp.rs +++ b/src/mcp.rs @@ -16,8 +16,8 @@ use crate::mcp_groups::{AgentTools, Selection, DISABLE_VAR, TOOLS_VAR}; pub struct GroupState { pub selection: Selection, pub warnings: Vec, - /// A switch is set or AGENTS.md has an `agent-tools` block. Only then does `initialize` - /// advertise `listChanged` and carry the groups line; otherwise every reply is as before. + /// A switch is set or AGENTS.md has an `agent-tools` block. Only then do `initialize` + /// and `list_core_tools` carry the groups line. pub shaped: bool, agents: Option, stamp: Option<(std::time::SystemTime, u64)>, @@ -481,13 +481,9 @@ pub fn handle_message(msg: &Json) -> Option { fn initialize() -> Json { let state = groups_state(); - // listChanged only when groups are in play, so a server with no switch and no block - // answers exactly as 5.1.0 did. - let tools = if state.shaped { - Json::obj(vec![("listChanged", Json::Bool(true))]) - } else { - Json::obj(vec![]) - }; + // listChanged is always advertised: an agent may add an agent-tools block mid-session. + // It is the one field that differs from 5.1.0 when no switch and no block are set. + let tools = Json::obj(vec![("listChanged", Json::Bool(true))]); let mut value = Json::obj(vec![ ("protocolVersion", Json::String("2024-11-05".into())), ( diff --git a/src/mcp.rs.wiki.md b/src/mcp.rs.wiki.md index 91eccba..b7c0b3a 100644 --- a/src/mcp.rs.wiki.md +++ b/src/mcp.rs.wiki.md @@ -2,6 +2,6 @@ **Role:** Stdio JSON-RPC MCP adapter over `src/api.rs`. -`tool_schema` describes one tool. `handle_message` answers one JSON-RPC request. `serve_stdio` reads messages from stdin. `configure` reads `WIKIFIER_TOOLS` / `WIKIFIER_DISABLE` and the AGENTS.md `agent-tools` block into a `GroupState` (exit 2 on an env mistake). Before each message `refresh` stats AGENTS.md and reloads it; when the tool list changed, `serve_stdio` writes `LIST_CHANGED` before the response. `active` and `groups_state` read the current state. `tools/list` lists only the tools `active` allows, `initialize` adds an `instructions` line and `list_core_tools` a `groups` line when either switch is set, and a call to a hidden tool returns `ToolDisabled`. `tools/call` sets `isError` when the payload has `success: false`. `resources/read` serves the library, health, pending, and journal resources. `prompts/get` returns a short user message. Each call runs on a thread and stops waiting after `WIKIFIER_MCP_DEADLINE_S` seconds (default 60). A timeout payload has `timed_out` and `may_still_complete`. +`tool_schema` describes one tool. `handle_message` answers one JSON-RPC request. `serve_stdio` reads messages from stdin. `configure` reads `WIKIFIER_TOOLS` / `WIKIFIER_DISABLE` and the AGENTS.md `agent-tools` block into a `GroupState` (exit 2 on an env mistake). Before each message `refresh` stats AGENTS.md and reloads it; when the tool list changed, `serve_stdio` writes `LIST_CHANGED` before the response. `active` and `groups_state` read the current state. `initialize` always advertises `tools.listChanged`. `tools/list` lists only the tools `active` allows, `initialize` adds an `instructions` line and `list_core_tools` a `groups` line when either switch is set, and a call to a hidden tool returns `ToolDisabled`. `tools/call` sets `isError` when the payload has `success: false`. `resources/read` serves the library, health, pending, and journal resources. `prompts/get` returns a short user message. Each call runs on a thread and stops waiting after `WIKIFIER_MCP_DEADLINE_S` seconds (default 60). A timeout payload has `timed_out` and `may_still_complete`. A `tools/call` that leaves out a required argument other than `project_root` (or sends it empty) gets `InvalidArguments` naming the missing field, the accepted fields, and the fields received. `project_root` falls back to `WIKIFIER_PROJECT_ROOT`, then the cwd. `update_maps` omits the edge list unless `edges: true`; `edges_persisted` still gives the count. `health` takes `limit` (adds `entries_total` when it cuts) and `summary`. `session_bootstrap` and `get_project_status` cap `files` at `MCP_BOOTSTRAP_FILES` (100) unless the call passes `limit` (`0` lists all). diff --git a/src/mcp_groups.rs b/src/mcp_groups.rs index 9533478..14cb0ae 100644 --- a/src/mcp_groups.rs +++ b/src/mcp_groups.rs @@ -272,7 +272,8 @@ impl Selection { /// This tool's lines from the first fenced `agent-tools` block of an AGENTS.md. #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct AgentTools { - /// An `agent-tools` block exists, whether or not it has a wikifier line. + /// An `agent-tools` block exists, whether or not it has a wikifier line. A block inside + /// another fence (a docs example) is text, not config. pub found: bool, pub tools: Option, pub disable: Option, diff --git a/tests/tool_groups.rs b/tests/tool_groups.rs index 585e197..8be3c72 100644 --- a/tests/tool_groups.rs +++ b/tests/tool_groups.rs @@ -53,7 +53,11 @@ fn mcp_in(dir: &std::path::Path, env: &[(&str, &str)], lines: &[&str]) -> Output { let mut stdin = child.stdin.take().unwrap(); for line in lines { - writeln!(stdin, "{line}").unwrap(); + // A server that refused its switches has already exited (exit 2); writing to + // it then fails with a broken pipe on Unix, and the exit status is what counts. + if writeln!(stdin, "{line}").is_err() { + break; + } } } child.wait_with_output().unwrap() @@ -251,15 +255,7 @@ fn default_initialize_and_tools_list_match_the_last_release() { // The same two requests the fixture was recorded with, from the 5.1.0 release binary. let list = r#"{"jsonrpc":"2.0","id":2,"method":"tools/list"}"#; let out = mcp(&[], &[INIT, list]); - let golden = std::fs::read_to_string( - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/mcp_default_5.1.0.jsonl"), - ) - .unwrap() - .replace("\r\n", "\n") - .replace( - "\"version\":\"5.1.0\"", - &format!("\"version\":\"{}\"", env!("CARGO_PKG_VERSION")), - ); + let golden = golden(); assert_eq!(String::from_utf8_lossy(&out.stdout), golden); } @@ -437,15 +433,7 @@ fn no_block_leaves_every_reply_as_before() { ) .unwrap(); assert_eq!(mcp_in(&dir, &[], &[INIT, list]).stdout, bare); - let golden = std::fs::read_to_string( - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/mcp_default_5.1.0.jsonl"), - ) - .unwrap() - .replace("\r\n", "\n") - .replace( - "\"version\":\"5.1.0\"", - &format!("\"version\":\"{}\"", env!("CARGO_PKG_VERSION")), - ); + let golden = golden(); assert_eq!(String::from_utf8_lossy(&bare), golden); } @@ -506,3 +494,39 @@ fn the_parser_reads_only_the_first_agent_tools_fence() { assert!(parsed.warnings.is_empty()); assert_eq!(AgentTools::parse("no block here"), AgentTools::default()); } + +/// What 5.1.0 answered to `initialize` and `tools/list`, with this version's number and the +/// one field the convention adds to every server: `capabilities.tools.listChanged`. +fn golden() -> String { + std::fs::read_to_string( + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/mcp_default_5.1.0.jsonl"), + ) + .unwrap() + .replace("\r\n", "\n") + .replace( + r#""version":"5.1.0""#, + &format!(r#""version":"{}""#, env!("CARGO_PKG_VERSION")), + ) + .replacen(r#""tools":{}"#, r#""tools":{"listChanged":true}"#, 1) +} + +/// This repository dogfoods its own MCP server. Its AGENTS.md documents the block, and those +/// examples must switch nothing: the repo keeps every tool. +#[test] +fn this_repos_agents_md_examples_switch_nothing() { + use wikifier::mcp_groups::AgentTools; + let here = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let text = std::fs::read_to_string(here.join("AGENTS.md")).unwrap(); + assert!(text.contains("wikifier: disable map, cycles, status")); + let parsed = AgentTools::parse(&text); + assert!(!parsed.found, "{parsed:?}"); + assert_eq!(parsed.tools, None); + assert_eq!(parsed.disable, None); + let got = replies(&mcp_in(&here, &[], &[INIT, LIST])); + assert_eq!(instructions_of(&got[0]), ""); + assert_eq!(names_of(&got[1]).len(), MCP_TOOLS.len()); + // The convention's own example shape, a block inside a markdown fence, is text too. + let nested = + AgentTools::parse("````markdown\n```agent-tools\nwikifier: disable notes\n```\n````\n"); + assert_eq!(nested, AgentTools::default()); +} From 2d2c2e438c8d13cf1810c10b14ac31741e50d9e2 Mon Sep 17 00:00:00 2001 From: IronAdamant <18153828+IronAdamant@users.noreply.github.com> Date: Thu, 5 Nov 2026 17:30:11 +1100 Subject: [PATCH 5/5] Dogfood: record the listChanged change. Generated by the wikifier binary, not edited by hand. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CMYkogM3QWVjMLzWKGyjuJ --- file_health.json | 2 +- file_health.md | 10 +++++----- journal/2026/11/05.md | 20 ++++++++++++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/file_health.json b/file_health.json index 6b39efc..4c329eb 100644 --- a/file_health.json +++ b/file_health.json @@ -1 +1 @@ -{"entries":{".github/workflows/publish.yml":{"last_updated":"2026-11-03 09:27:04","reason":"Multi-target release archives and SHA256SUMS (subid=release-5.0.0)","source_content_hash":"sha256:930170e1eb57afbe2850a0e9c2ac179eb2b5947bf2f74d4292bcd2b0099ab8de","source_mtime_ns":"1793697915725124882","status":"🟢 Green","verification":"no_wiki"},"AGENTS.md":{"last_updated":"2026-11-05 06:26:37","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:a1fe8322f6c0f7b7fcb11ca7c510221419c9c4f15766b1ac6b1e67380c073801","source_mtime_ns":"1793859884410457800","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:32978113ded2badae40362bec72701f620e9954a1155286e7555af7d316d6888"},"CHANGELOG.md":{"last_updated":"2026-11-05 06:26:17","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:203636ef79dd12e90d7052dd7bf37960c22315a1a732568a5aeb27b7f2b9874c","source_mtime_ns":"1793859902655868900","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:757601288624e346279cef86383a88cdf7c1c467e7c6538f40c05d475e243de8"},"CLAUDE.md":{"last_updated":"2026-11-05 06:26:17","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:5200118c6eef8e19569e72d84ee275fcf797efffc12b553313f8218766c09de0","source_mtime_ns":"1793859902657869100","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:74e98420d628c198740b9aa32877dd0a20956285f22648e5d6eb5728c692456d"},"CONTRIBUTING.md":{"last_updated":"2026-11-03 05:34:35","reason":"Address the 3 Nov review findings (subid=review-2026-11-03)","source_content_hash":"sha256:d090280cd3d1c3ab1cf342d69392471ed3835512ff7381bf4409bada57bbe89c","source_mtime_ns":"1793683924316411256","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:ec0bd9342b8e9dfeefaabc8dcddeb577f6bd4f1c760d7286b21d709c2a372b29"},"Cargo.lock":{"last_updated":"2026-11-05 06:20:18","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:33ae77a3977a89f75506f16f2add899c3961d7dc276235eb9973d01bbdc9740c","source_mtime_ns":"1793859367585833600","status":"🟢 Green","verification":"no_wiki"},"Cargo.toml":{"last_updated":"2026-11-05 06:20:18","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:abdbf324522c70b251f4bb22cca3ffb05862327078a2c94ff4ba1373e87fa37a","source_mtime_ns":"1793859367584833600","status":"🟢 Green","verification":"no_wiki"},"Findings/M5-Dogfood-Assessment-Report.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:238435188b1699e5bcf4753b62a6fe55cb064413a291259f0b696b5bd3c1692f","source_mtime_ns":"1780519956000000000","status":"🟢 Green"},"Findings/M5-Dogfood-Progress.md":{"last_updated":"2026-11-03 08:06:46","reason":"Wiki marks this file as the historical M5 log (subid=protocol-v07)","source_content_hash":"sha256:ef55167e819806060dfd7dfe7cdfd4d02024ca97706a7faa243710e2630b65fe","source_mtime_ns":"1793408707259550076","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:b6b1fa4bbee0c7e8c4035cd925f6d07e1221ba483e3472878d5b88236c5cf7f9"},"Findings/M5.1-cross-hardening-analysis.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:a2c2414e5b6c9b1a802bec8734a7924850d546cd7746a8087216f3685ca36cb4","source_mtime_ns":"1780519762000000000","status":"🟢 Green"},"Findings/Milestones-Overview.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:f8b7030ec8980774cf3a2560ad7aee6537263eadf8374e650718f7c6793c6d50","source_mtime_ns":"1780800604000000000","status":"🟢 Green"},"Findings/p6_real_world_validation_report.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:0468224675888f2747674324726c0ea9a5dddded39d9a1a50f22fc3357dafc0f","source_mtime_ns":"1780520008000000000","status":"🟢 Green"},"README.md":{"last_updated":"2026-11-05 06:26:37","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:2a1a4aa3fe86c2859668b5eb6cd2d8a94d226df67e6580caa6d9e9f0b42c68f3","source_mtime_ns":"1793859902652877900","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:a50d4ce8314239a0fa5ef1d86f3f9f3337bb861473ffa2fd380bb58450ccd821"},"docs/spec.md":{"last_updated":"2026-11-03 08:00:11","reason":"Name the Rust binary and protocol v0.7 in the living principles (subid=protocol-v07)","source_content_hash":"sha256:31fe6b3b3d705628692eb0512cf44cbb21861ccfc5bb02afdd46d796ec066c6e","source_mtime_ns":"1793653008580824356","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:a58b929d25d510f15f9fe176d7823e852f6d089e398accc2e22e1ed189f260ac"},"scripts/benchmark_parity.sh":{"last_updated":"2026-11-03 08:56:15","reason":"Benchmark script and measured results.","source_content_hash":"sha256:b8f72e3245e77b9df17b303293d8cbe4a93cc36023c41b89a794b77b01daef87","status":"🟡 Yellow"},"scripts/benchmark_results.md":{"last_updated":"2026-11-03 08:56:15","reason":"Benchmark script and measured results.","source_content_hash":"sha256:8bf9342fce85f126a37f812b03b6f6997f1fe8e7c5176d30301c1a4a15aeee29","status":"🟡 Yellow"},"skills/run.md":{"last_updated":"2026-11-05 06:26:17","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:7fcc6b45009f88d76848a3c49499cec67328099e2e5a7fe1905f9e8ed14f9232","source_mtime_ns":"1793859884411457500","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:8a544f844e020c77db88bedaa7b2f05a167408c7f089521a7be5d9cfc2c233b9"},"src/api.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"MapRun\nVERSION\nMCP_TOOLS\nupdate_maps\nupdate_maps_opts\nupdate_maps_run\nseed_source_hashes\nmapped_edges\nload_dependencies\ndependency_report\nload_dependents\nlist_paths\nlist_paths_at\nsession_bootstrap\nsession_bootstrap_scoped\nsuggest_next_actions\nsuggest_next_scoped\ncheck_changes\nprepare_edit\nrecord_change\nmark_green\nhealth\nhealth_view\nread_health\nread_journal\ncache_status\nvalidate\ncycles\ncycles_view\nverify_wikis\nrecord_changes\nrecord_changes_opts\nrecord_deletion\nheal_stubs\nprune_health\nprune_health_opts\nprune_pending\nstale_wikis\nstale_wikis_in\nprune_barrels\nmetrics_snapshot\nhealing_stats\nresolution_diagnostics\nbarrel_reports\nincremental_status\nserve_once\nserve_loop\nmonitor_loop\ndaemon_ctl\ndaemon_command\ndispatch\nCLI_COMMANDS\nensure_root","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:f5575d808fab6a3334acd6af46c1f926b15156993828a21be86e7335487baab2","source_mtime_ns":"1793856867181743100","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:1959bc30bd0758cbcbef5c2c1da7bf2599b044f8f954f8d9043ca7e794590a7a"},"src/artifacts.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"HealthRow\nwrite_durable\nread_health\nwrite_health\nupsert_health_row\nJournalEntry\njournal_path\nread_journal\nparse_journal\nJournalWrite\nappend_journal\nread_pending\nfolder_card\nnew\nkeep_baseline_from","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:c5989a5fe22edf99afab4b4721fda9f45a12faff19d9f1a97277fcf1003d1ffd","source_mtime_ns":"1793856655049237400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:751e2374f151dc19c0d20ff447db2ce26b908af28067a7e74ef3a0502ce51bc2"},"src/cache.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"check_consistency\nrebuild\nConsistency\nSession\npayload_path\nby_src_path\ncommit_pending_path\nload_dependencies\nInternalEdge\nconfidence_of\nformat_edge_line\nDependencyView\nload_dependency_view\nload_internal_edges\nload_dependents\nlist_prefix\nall_paths\nFileUpdate\nupsert_file\nremove_file\nindexed_rows\nindex_by_path\nhash_if_unchanged\npayload_bytes\nstat_ns\nedges\nrel_string\nwrite_barrel_record\nprune_barrel_files\nconfidence\nacs_reason","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:d0e30e9031d1259333ebeb7799ad78c1836135fa762197d3512f7193640ed6af","source_mtime_ns":"1793856524124108400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:a48d3652a05cb7e208651c63045e714c62ba5ea1fd7e19fac3b9df84c1af31de"},"src/cache_commit.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"Consistency\nSession\ncheck_consistency\nrebuild\nopen\nknown\ndsts_of\nnote_stat\nrels\nupsert\nremove\nstage_barrel\nhas_changes\nneeds_parse\ncommit","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:fb1f90a3d27558ed141eba2d8fb408bc76a47b2c6715096dba5e75819809513f","source_mtime_ns":"1793856524408983600","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:60c2ba29a68f5feb2a5dd69b9a99d550c6d288386f2a822811eb1530742bf336"},"src/cycle_report.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:db35b610d9a9f9917805da9383e61872e66e640482f57fc9e17ae91daf77fe3d","status":"🟡 Yellow"},"src/daemon_svc.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:0887baeb3ad7f2fca851fccc0d9335dafd4b42f3e54e236175a13d39c5bcd063","status":"🟡 Yellow"},"src/jsonutil.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"Json\nparse\nparse_jsonc\nstrip_json_comments\nobj\nfrom_pairs\nget\nas_str\nas_bool\nas_array\nas_object\ninsert\nfmt","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:cb71e00e352df010928a42323d6d87bbe67348834a209348fc174b9d00489676","source_mtime_ns":"1793684429116993727","status":"🟡 Yellow","wiki_hash":"sha256:fb4cffba8b14a179dd90f201b61df2608ca78a9775e9646e7f011f1b9fa07c63"},"src/legacy_cache.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"import_if_empty","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:a127d0b1742d69b736194ca98579f5fc0611fc51a291d691aef6fe586fd68ba3","source_mtime_ns":"1793683981803718735","status":"🟡 Yellow","wiki_hash":"sha256:a6fe6c79185a46cc4b30d215475bab28f517f6e5a6fd7bce6423c2792814aac8"},"src/lib.rs":{"last_updated":"2026-11-05 06:26:16","public_symbols":"api\nartifacts\ncache\njsonutil\nmaps_out\nmcp\nmcp_groups\nparse\nscope\nsha256\nsymbols\ntext_out\ntimeutil\ncache_status\ncheck_changes\nhealth\nlist_paths\nload_dependencies\nload_dependents\nmapped_edges\nmark_green\nprepare_edit\nread_health\nread_journal\nrecord_change\nsession_bootstrap\nsuggest_next_actions\nupdate_maps\nVERSION\nJson","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:1c24582b84c5ffb3782eb2c68f4cb3694d994621b9c6d1ca416cc759a0159338","source_mtime_ns":"1793859251665208600","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:5951135711c2a9705e7351529044dec9fcb95de6f7840062faeee9d6c4e9d318"},"src/low_conf.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:3ade5fc70ce585a48b9acf6a2b48753e58e80f63281a31c8b8453816700b375e","status":"🟡 Yellow"},"src/main.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:2b3cebdafca3ca3da7831101a63b36f72260b3b2879871e5364b427428e782e0","source_mtime_ns":"1793683990351610198","status":"🟡 Yellow","wiki_hash":"sha256:db6e1cd5beeb90e5a65b3e00a37ee2c73ea4c53750771151e655459a1b823ff5"},"src/maps_out.rs":{"last_updated":"2026-11-05 05:15:33","public_symbols":"current\nwrite\nwrite_status\nread_status","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:4223756e3ddd7a7317d364f5de9bbffe1fe59e820b0b8187164bd30449039432","source_mtime_ns":"1793854043821084000","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:5218571835e011f1f33b83b5a57723204910bb8209a5f88a1a2d3a06ee82e30a"},"src/mcp.rs":{"last_updated":"2026-11-05 06:26:16","public_symbols":"GroupState\nLIST_CHANGED\nactive\ngroups_state\nconfigure\nrefresh\ntool_schema\nhandle_message\nserve_stdio\ninstructions","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:86e934f010854b378356746f7c22026f34bf3448a15fddd010d7ffcf9c29d4e3","source_mtime_ns":"1793859786351065300","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:6bbb0766ec896835b385a13b6d83d9be30de70652ad12c6b3c2a00c230616e54"},"src/mcp_groups.rs":{"last_updated":"2026-11-05 06:26:16","public_symbols":"TOOLS_VAR\nDISABLE_VAR\nGROUPS\ngroup_of\nSource\nSelection\nAgentTools\nall\nfrom_env\nparse\nresolve\nis_filtered\nallows\nenabled\nrefusal\nactive_groups\nsummary","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:c85c6f1995109fc3c10556058463cc5e73e37204cc7da9999140d26f1cb445ce","source_mtime_ns":"1793859786781809400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:b621998ab1e53122af6eedfaa18f9772c93d2681d0158a6add8f4661ef5540f1"},"src/parse.rs":{"last_updated":"2026-11-05 05:15:33","public_symbols":"RawImport\nKind\nScan\nlanguage\nread_utf8\nscan_file_warned\nscan_file\nresolve_project\nrust_public_symbols\nresolve_python_spec\nFactEdge\nFileFacts\nAnalysis\nanalyze_files\nanalyze_changed\nedges_for_files","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:4122cf1ec797e2af0a410dcf13d6cfb3f087410db5dcae27cff7c79cbdd88228","source_mtime_ns":"1793855453252350400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:3ea6562f6fbb69c3510cba443a994caa2dbab3fae30e290847ec1cd43913e047"},"src/pending_line.rs":{"last_updated":"2026-11-05 05:19:31","public_symbols":"file_of\nformat_item\nEMPTY_NOTE\nappend_item\nremove_item\nrecord_message\nCHECK_MESSAGE","reason":"wiki (claude/windows-verify pending)","source_content_hash":"sha256:f1ad66b1c330ce490b36a72d58cb2a341b0f44b0b5ec2166cd943a83cf694d05","source_mtime_ns":"1793855871596115600","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:3bac5aead2f3a0b020e056fe388d7670f9a3b45d79be75d197f5b71966620f56"},"src/proc.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:8f13798a8b9289d78913becc626056c8b016838570e356e09bfa3333e800351c","status":"🟡 Yellow"},"src/project_lock.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"ProjectLock\ndrop\nacquire","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:194e329f35ff59b11fc734b980a1ee33f8e464bcdb5eae899486e487daef3a25","source_mtime_ns":"1793678007370625780","status":"🟡 Yellow","wiki_hash":"sha256:fccc8d547f30262ff64d506d842472623e828ebe39fde71532a683c6956329d2"},"src/scope.rs":{"last_updated":"2026-11-05 05:15:34","public_symbols":"SOURCE_EXTS\nScope\ndetect\nread_path_list\nexcludes\nis_source\ncollect\nrel_of\ndefault_map_roots\nrel_arg\nallows_walk","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:0843deef3d82162edf7bac2c53c9a9f716735b4e639451f7fb36620de2dcd059","source_mtime_ns":"1793854073257790700","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:574d4cc8bd261700b1e192628435926d8f1e533f7f1967e27eb6c797e59e6c0e"},"src/sha256.rs":{"last_updated":"2026-11-05 04:14:08","public_symbols":"sha256\nsha256_hex\nsha256_prefixed\ncontent_sha256_prefixed\nfile_sha256_prefixed","reason":"wiki updated (claude/windows-verify)","source_content_hash":"sha256:2f4f8a8ccb9f9d4748fc0678e6bac63dc69ade57e9ab4b3c6eb2a1c43fcf5c14","source_mtime_ns":"1793851995838527400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:0d1d67e61bed7a20c6a8413a352a55fb87f05bda6e39760015727d128a67ae33"},"src/symbols.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:4a150ba04e9ea26020c874c5e256a9ec5acc3ef4d621fb6ff03b21935c3f8046","status":"🟡 Yellow"},"src/text_out.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:8e0edc1141a2c1745c0e6fdd7a7645c7332365fac532d52fb3e188f4ef06148e","status":"🟡 Yellow"},"src/timeutil.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:9921127144d9d40619e260753e700e9c8a47135ed95b2ad8791afb7fe78afd75","status":"🟡 Yellow"},"src/wiki_files.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:2612539ce9092a3d126d80ce2947f6b4555ddb0bb335769b1619ec67d08a5e84","status":"🟡 Yellow"},"tests/agent_args.rs":{"last_updated":"2026-11-05 04:14:08","reason":"new: agent-style file args, missing args, lean MCP outputs, init roots, CRLF (claude/windows-verify)","source_content_hash":"sha256:ae25dcc233b1d40c48dbc7199e350032717412316089084751b9280970feb66d","status":"🟡 Yellow"},"tests/behaviour_gaps.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:8c8d669dae2dbe39b88c2223d20fb2fca51ac1605c62edd108d6ef224223402b","source_mtime_ns":"1793684893298602299","status":"🟡 Yellow","wiki_hash":"sha256:b9d20a310ca48ffd858e6d0d4e49b5e0568ecb57dc5ad981eb54398562864691"},"tests/cache_and_artifacts.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:b9483666c1e19f90d4db1af718b08beebadfbcba66152497b7694d8e757a5ec1","status":"🟡 Yellow"},"tests/cli_surface.rs":{"last_updated":"2026-11-05 05:37:11","reason":"docs name the Cargo version (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:0aef6e3256a524e014971637bad8a928deba528b734995728bfb72ea606730f5","status":"🟡 Yellow"},"tests/contract_gaps.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:dc91a239bbc615524b4ac2c58d06515183dfc4981309906003f551e6721d82ae","status":"🟡 Yellow"},"tests/dogfood.rs":{"last_updated":"2026-11-05 06:20:17","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:36af6c04119986796434bcf75be9095cd2c28d7e0df476c72463343181c83328","source_mtime_ns":"1793859367674990400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:0bc5f3d78d1779ba6302ecc406dc0b25d8beda25f1681a26d57e97210df19906"},"tests/parity.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:0246038a1cc01bf66da2fd186ede61f2dcd2c98da9c0c90dd7f3b2cbab1036db","source_mtime_ns":"1793683314773282057","status":"🟡 Yellow","wiki_hash":"sha256:32753c244642df6e08f8578c6203f77225363783c15bc57c33a84f03989f2378"},"tests/parity_fixes.rs":{"last_updated":"2026-11-05 05:15:33","reason":"pending item wording and empty-queue note (claude/windows-verify speed)","source_content_hash":"sha256:b74f37dffb2a5bbcc8724298885a677a9d4476f846791d31770798e0a6caa7a3","status":"🟡 Yellow"},"tests/protocol_v07.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:bb7cffecabc3fb51ebcc77c64f7fd78f5cd15c445d7e13493ed491227280f37d","source_mtime_ns":"1793684781738827745","status":"🟡 Yellow","wiki_hash":"sha256:b38f4a13e316cefd56070f822980b4f83d9cdacb850ab1978de48ed35c630ec8"},"tests/robustness.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:fad304193a47baa8cce21cff8786b35974c7c7f6f71b3318edeb68bd60121681","status":"🟡 Yellow"},"tests/skip_maps.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:2eed0c6bc97d91a4be3f2b6ab08c78c62a3a05725a503496e3df91abad6b2130","status":"🟡 Yellow"},"tests/speed_paths.rs":{"last_updated":"2026-11-05 05:37:11","reason":"self-heal and durable user-state tests (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:a9348e032c3ffd9f6960710b364470cbcbf935f366af604dd2ad62ac4f2a7a9e","status":"🟡 Yellow"},"tests/tool_groups.rs":{"last_updated":"2026-11-05 06:26:16","reason":"agent-chosen tool groups from the AGENTS.md agent-tools block, list_changed on edits (claude/tool-groups)","source_content_hash":"sha256:892fbc4330f902ac0fb01b8d8ea5c8c018ca7422408ea759853a8b3d8cf711c6","status":"🟡 Yellow"},"wikifier.sh":{"last_updated":"2026-11-03 08:06:46","reason":"Wiki describes the Rust binary launcher (subid=protocol-v07)","source_content_hash":"sha256:4f467e2117e8c361882054998cb0506717d9555e2aa570f0e176fc18d9c2f4aa","source_mtime_ns":"1793410024331635951","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:3876708eaec60862b9b8b6f73e2ae87e4abca2f228c456f973ddb7c9ee36854a"}},"version":2} \ No newline at end of file +{"entries":{".github/workflows/publish.yml":{"last_updated":"2026-11-03 09:27:04","reason":"Multi-target release archives and SHA256SUMS (subid=release-5.0.0)","source_content_hash":"sha256:930170e1eb57afbe2850a0e9c2ac179eb2b5947bf2f74d4292bcd2b0099ab8de","source_mtime_ns":"1793697915725124882","status":"🟢 Green","verification":"no_wiki"},"AGENTS.md":{"last_updated":"2026-11-05 06:26:37","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:a1fe8322f6c0f7b7fcb11ca7c510221419c9c4f15766b1ac6b1e67380c073801","source_mtime_ns":"1793859884410457800","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:32978113ded2badae40362bec72701f620e9954a1155286e7555af7d316d6888"},"CHANGELOG.md":{"last_updated":"2026-11-05 06:30:10","reason":"wiki updated (claude/tool-groups listChanged)","source_content_hash":"sha256:e47b1214881496ae2105ebe8394c5cc8ab9152ea09b9e382ba63922e449aa140","source_mtime_ns":"1793860168832819200","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:757601288624e346279cef86383a88cdf7c1c467e7c6538f40c05d475e243de8"},"CLAUDE.md":{"last_updated":"2026-11-05 06:26:17","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:5200118c6eef8e19569e72d84ee275fcf797efffc12b553313f8218766c09de0","source_mtime_ns":"1793859902657869100","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:74e98420d628c198740b9aa32877dd0a20956285f22648e5d6eb5728c692456d"},"CONTRIBUTING.md":{"last_updated":"2026-11-03 05:34:35","reason":"Address the 3 Nov review findings (subid=review-2026-11-03)","source_content_hash":"sha256:d090280cd3d1c3ab1cf342d69392471ed3835512ff7381bf4409bada57bbe89c","source_mtime_ns":"1793683924316411256","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:ec0bd9342b8e9dfeefaabc8dcddeb577f6bd4f1c760d7286b21d709c2a372b29"},"Cargo.lock":{"last_updated":"2026-11-05 06:20:18","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:33ae77a3977a89f75506f16f2add899c3961d7dc276235eb9973d01bbdc9740c","source_mtime_ns":"1793859367585833600","status":"🟢 Green","verification":"no_wiki"},"Cargo.toml":{"last_updated":"2026-11-05 06:20:18","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:abdbf324522c70b251f4bb22cca3ffb05862327078a2c94ff4ba1373e87fa37a","source_mtime_ns":"1793859367584833600","status":"🟢 Green","verification":"no_wiki"},"Findings/M5-Dogfood-Assessment-Report.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:238435188b1699e5bcf4753b62a6fe55cb064413a291259f0b696b5bd3c1692f","source_mtime_ns":"1780519956000000000","status":"🟢 Green"},"Findings/M5-Dogfood-Progress.md":{"last_updated":"2026-11-03 08:06:46","reason":"Wiki marks this file as the historical M5 log (subid=protocol-v07)","source_content_hash":"sha256:ef55167e819806060dfd7dfe7cdfd4d02024ca97706a7faa243710e2630b65fe","source_mtime_ns":"1793408707259550076","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:b6b1fa4bbee0c7e8c4035cd925f6d07e1221ba483e3472878d5b88236c5cf7f9"},"Findings/M5.1-cross-hardening-analysis.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:a2c2414e5b6c9b1a802bec8734a7924850d546cd7746a8087216f3685ca36cb4","source_mtime_ns":"1780519762000000000","status":"🟢 Green"},"Findings/Milestones-Overview.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:f8b7030ec8980774cf3a2560ad7aee6537263eadf8374e650718f7c6793c6d50","source_mtime_ns":"1780800604000000000","status":"🟢 Green"},"Findings/p6_real_world_validation_report.md":{"last_updated":"2026-07-09 05:02:27","reason":"kept; stale yellow cleared","source_content_hash":"sha256:0468224675888f2747674324726c0ea9a5dddded39d9a1a50f22fc3357dafc0f","source_mtime_ns":"1780520008000000000","status":"🟢 Green"},"README.md":{"last_updated":"2026-11-05 06:30:10","reason":"wiki updated (claude/tool-groups listChanged)","source_content_hash":"sha256:748e0268fd822083f2ddd3a11a2fa087af1e43213747433b39312dd7ab44f43e","source_mtime_ns":"1793860168835171600","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:a50d4ce8314239a0fa5ef1d86f3f9f3337bb861473ffa2fd380bb58450ccd821"},"docs/spec.md":{"last_updated":"2026-11-03 08:00:11","reason":"Name the Rust binary and protocol v0.7 in the living principles (subid=protocol-v07)","source_content_hash":"sha256:31fe6b3b3d705628692eb0512cf44cbb21861ccfc5bb02afdd46d796ec066c6e","source_mtime_ns":"1793653008580824356","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:a58b929d25d510f15f9fe176d7823e852f6d089e398accc2e22e1ed189f260ac"},"scripts/benchmark_parity.sh":{"last_updated":"2026-11-03 08:56:15","reason":"Benchmark script and measured results.","source_content_hash":"sha256:b8f72e3245e77b9df17b303293d8cbe4a93cc36023c41b89a794b77b01daef87","status":"🟡 Yellow"},"scripts/benchmark_results.md":{"last_updated":"2026-11-03 08:56:15","reason":"Benchmark script and measured results.","source_content_hash":"sha256:8bf9342fce85f126a37f812b03b6f6997f1fe8e7c5176d30301c1a4a15aeee29","status":"🟡 Yellow"},"skills/run.md":{"last_updated":"2026-11-05 06:26:17","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:7fcc6b45009f88d76848a3c49499cec67328099e2e5a7fe1905f9e8ed14f9232","source_mtime_ns":"1793859884411457500","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:8a544f844e020c77db88bedaa7b2f05a167408c7f089521a7be5d9cfc2c233b9"},"src/api.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"MapRun\nVERSION\nMCP_TOOLS\nupdate_maps\nupdate_maps_opts\nupdate_maps_run\nseed_source_hashes\nmapped_edges\nload_dependencies\ndependency_report\nload_dependents\nlist_paths\nlist_paths_at\nsession_bootstrap\nsession_bootstrap_scoped\nsuggest_next_actions\nsuggest_next_scoped\ncheck_changes\nprepare_edit\nrecord_change\nmark_green\nhealth\nhealth_view\nread_health\nread_journal\ncache_status\nvalidate\ncycles\ncycles_view\nverify_wikis\nrecord_changes\nrecord_changes_opts\nrecord_deletion\nheal_stubs\nprune_health\nprune_health_opts\nprune_pending\nstale_wikis\nstale_wikis_in\nprune_barrels\nmetrics_snapshot\nhealing_stats\nresolution_diagnostics\nbarrel_reports\nincremental_status\nserve_once\nserve_loop\nmonitor_loop\ndaemon_ctl\ndaemon_command\ndispatch\nCLI_COMMANDS\nensure_root","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:f5575d808fab6a3334acd6af46c1f926b15156993828a21be86e7335487baab2","source_mtime_ns":"1793856867181743100","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:1959bc30bd0758cbcbef5c2c1da7bf2599b044f8f954f8d9043ca7e794590a7a"},"src/artifacts.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"HealthRow\nwrite_durable\nread_health\nwrite_health\nupsert_health_row\nJournalEntry\njournal_path\nread_journal\nparse_journal\nJournalWrite\nappend_journal\nread_pending\nfolder_card\nnew\nkeep_baseline_from","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:c5989a5fe22edf99afab4b4721fda9f45a12faff19d9f1a97277fcf1003d1ffd","source_mtime_ns":"1793856655049237400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:751e2374f151dc19c0d20ff447db2ce26b908af28067a7e74ef3a0502ce51bc2"},"src/cache.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"check_consistency\nrebuild\nConsistency\nSession\npayload_path\nby_src_path\ncommit_pending_path\nload_dependencies\nInternalEdge\nconfidence_of\nformat_edge_line\nDependencyView\nload_dependency_view\nload_internal_edges\nload_dependents\nlist_prefix\nall_paths\nFileUpdate\nupsert_file\nremove_file\nindexed_rows\nindex_by_path\nhash_if_unchanged\npayload_bytes\nstat_ns\nedges\nrel_string\nwrite_barrel_record\nprune_barrel_files\nconfidence\nacs_reason","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:d0e30e9031d1259333ebeb7799ad78c1836135fa762197d3512f7193640ed6af","source_mtime_ns":"1793856524124108400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:a48d3652a05cb7e208651c63045e714c62ba5ea1fd7e19fac3b9df84c1af31de"},"src/cache_commit.rs":{"last_updated":"2026-11-05 05:37:12","public_symbols":"Consistency\nSession\ncheck_consistency\nrebuild\nopen\nknown\ndsts_of\nnote_stat\nrels\nupsert\nremove\nstage_barrel\nhas_changes\nneeds_parse\ncommit","reason":"wiki updated (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:fb1f90a3d27558ed141eba2d8fb408bc76a47b2c6715096dba5e75819809513f","source_mtime_ns":"1793856524408983600","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:60c2ba29a68f5feb2a5dd69b9a99d550c6d288386f2a822811eb1530742bf336"},"src/cycle_report.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:db35b610d9a9f9917805da9383e61872e66e640482f57fc9e17ae91daf77fe3d","status":"🟡 Yellow"},"src/daemon_svc.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:0887baeb3ad7f2fca851fccc0d9335dafd4b42f3e54e236175a13d39c5bcd063","status":"🟡 Yellow"},"src/jsonutil.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"Json\nparse\nparse_jsonc\nstrip_json_comments\nobj\nfrom_pairs\nget\nas_str\nas_bool\nas_array\nas_object\ninsert\nfmt","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:cb71e00e352df010928a42323d6d87bbe67348834a209348fc174b9d00489676","source_mtime_ns":"1793684429116993727","status":"🟡 Yellow","wiki_hash":"sha256:fb4cffba8b14a179dd90f201b61df2608ca78a9775e9646e7f011f1b9fa07c63"},"src/legacy_cache.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"import_if_empty","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:a127d0b1742d69b736194ca98579f5fc0611fc51a291d691aef6fe586fd68ba3","source_mtime_ns":"1793683981803718735","status":"🟡 Yellow","wiki_hash":"sha256:a6fe6c79185a46cc4b30d215475bab28f517f6e5a6fd7bce6423c2792814aac8"},"src/lib.rs":{"last_updated":"2026-11-05 06:26:16","public_symbols":"api\nartifacts\ncache\njsonutil\nmaps_out\nmcp\nmcp_groups\nparse\nscope\nsha256\nsymbols\ntext_out\ntimeutil\ncache_status\ncheck_changes\nhealth\nlist_paths\nload_dependencies\nload_dependents\nmapped_edges\nmark_green\nprepare_edit\nread_health\nread_journal\nrecord_change\nsession_bootstrap\nsuggest_next_actions\nupdate_maps\nVERSION\nJson","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:1c24582b84c5ffb3782eb2c68f4cb3694d994621b9c6d1ca416cc759a0159338","source_mtime_ns":"1793859251665208600","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:5951135711c2a9705e7351529044dec9fcb95de6f7840062faeee9d6c4e9d318"},"src/low_conf.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:3ade5fc70ce585a48b9acf6a2b48753e58e80f63281a31c8b8453816700b375e","status":"🟡 Yellow"},"src/main.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:2b3cebdafca3ca3da7831101a63b36f72260b3b2879871e5364b427428e782e0","source_mtime_ns":"1793683990351610198","status":"🟡 Yellow","wiki_hash":"sha256:db6e1cd5beeb90e5a65b3e00a37ee2c73ea4c53750771151e655459a1b823ff5"},"src/maps_out.rs":{"last_updated":"2026-11-05 05:15:33","public_symbols":"current\nwrite\nwrite_status\nread_status","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:4223756e3ddd7a7317d364f5de9bbffe1fe59e820b0b8187164bd30449039432","source_mtime_ns":"1793854043821084000","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:5218571835e011f1f33b83b5a57723204910bb8209a5f88a1a2d3a06ee82e30a"},"src/mcp.rs":{"last_updated":"2026-11-05 06:30:10","public_symbols":"GroupState\nLIST_CHANGED\nactive\ngroups_state\nconfigure\nrefresh\ntool_schema\nhandle_message\nserve_stdio\ninstructions","reason":"wiki updated (claude/tool-groups listChanged)","source_content_hash":"sha256:1b902e215272220af849490b23d4be754e320f2ccf7345b2f54c7a8adb7f945a","source_mtime_ns":"1793860108104603100","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:947835e38629a08ee80633f14b1aebaabdc8684836988a8139515d0f4d01b526"},"src/mcp_groups.rs":{"last_updated":"2026-11-05 06:30:10","public_symbols":"TOOLS_VAR\nDISABLE_VAR\nGROUPS\ngroup_of\nSource\nSelection\nAgentTools\nall\nfrom_env\nparse\nresolve\nis_filtered\nallows\nenabled\nrefusal\nactive_groups\nsummary","reason":"wiki updated (claude/tool-groups listChanged)","source_content_hash":"sha256:38bdd3f059c7b5cb2f9c3fae84ff65cabb3904d2a389aa7aa2176f0ed3ee63db","source_mtime_ns":"1793860092677265900","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:b621998ab1e53122af6eedfaa18f9772c93d2681d0158a6add8f4661ef5540f1"},"src/parse.rs":{"last_updated":"2026-11-05 05:15:33","public_symbols":"RawImport\nKind\nScan\nlanguage\nread_utf8\nscan_file_warned\nscan_file\nresolve_project\nrust_public_symbols\nresolve_python_spec\nFactEdge\nFileFacts\nAnalysis\nanalyze_files\nanalyze_changed\nedges_for_files","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:4122cf1ec797e2af0a410dcf13d6cfb3f087410db5dcae27cff7c79cbdd88228","source_mtime_ns":"1793855453252350400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:3ea6562f6fbb69c3510cba443a994caa2dbab3fae30e290847ec1cd43913e047"},"src/pending_line.rs":{"last_updated":"2026-11-05 05:19:31","public_symbols":"file_of\nformat_item\nEMPTY_NOTE\nappend_item\nremove_item\nrecord_message\nCHECK_MESSAGE","reason":"wiki (claude/windows-verify pending)","source_content_hash":"sha256:f1ad66b1c330ce490b36a72d58cb2a341b0f44b0b5ec2166cd943a83cf694d05","source_mtime_ns":"1793855871596115600","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:3bac5aead2f3a0b020e056fe388d7670f9a3b45d79be75d197f5b71966620f56"},"src/proc.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:8f13798a8b9289d78913becc626056c8b016838570e356e09bfa3333e800351c","status":"🟡 Yellow"},"src/project_lock.rs":{"last_updated":"2026-11-03 08:56:14","public_symbols":"ProjectLock\ndrop\nacquire","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:194e329f35ff59b11fc734b980a1ee33f8e464bcdb5eae899486e487daef3a25","source_mtime_ns":"1793678007370625780","status":"🟡 Yellow","wiki_hash":"sha256:fccc8d547f30262ff64d506d842472623e828ebe39fde71532a683c6956329d2"},"src/scope.rs":{"last_updated":"2026-11-05 05:15:34","public_symbols":"SOURCE_EXTS\nScope\ndetect\nread_path_list\nexcludes\nis_source\ncollect\nrel_of\ndefault_map_roots\nrel_arg\nallows_walk","reason":"wiki updated (claude/windows-verify speed)","source_content_hash":"sha256:0843deef3d82162edf7bac2c53c9a9f716735b4e639451f7fb36620de2dcd059","source_mtime_ns":"1793854073257790700","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:574d4cc8bd261700b1e192628435926d8f1e533f7f1967e27eb6c797e59e6c0e"},"src/sha256.rs":{"last_updated":"2026-11-05 04:14:08","public_symbols":"sha256\nsha256_hex\nsha256_prefixed\ncontent_sha256_prefixed\nfile_sha256_prefixed","reason":"wiki updated (claude/windows-verify)","source_content_hash":"sha256:2f4f8a8ccb9f9d4748fc0678e6bac63dc69ade57e9ab4b3c6eb2a1c43fcf5c14","source_mtime_ns":"1793851995838527400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:0d1d67e61bed7a20c6a8413a352a55fb87f05bda6e39760015727d128a67ae33"},"src/symbols.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:4a150ba04e9ea26020c874c5e256a9ec5acc3ef4d621fb6ff03b21935c3f8046","status":"🟡 Yellow"},"src/text_out.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:8e0edc1141a2c1745c0e6fdd7a7645c7332365fac532d52fb3e188f4ef06148e","status":"🟡 Yellow"},"src/timeutil.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:9921127144d9d40619e260753e700e9c8a47135ed95b2ad8791afb7fe78afd75","status":"🟡 Yellow"},"src/wiki_files.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions.","source_content_hash":"sha256:2612539ce9092a3d126d80ce2947f6b4555ddb0bb335769b1619ec67d08a5e84","status":"🟡 Yellow"},"tests/agent_args.rs":{"last_updated":"2026-11-05 04:14:08","reason":"new: agent-style file args, missing args, lean MCP outputs, init roots, CRLF (claude/windows-verify)","source_content_hash":"sha256:ae25dcc233b1d40c48dbc7199e350032717412316089084751b9280970feb66d","status":"🟡 Yellow"},"tests/behaviour_gaps.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:8c8d669dae2dbe39b88c2223d20fb2fca51ac1605c62edd108d6ef224223402b","source_mtime_ns":"1793684893298602299","status":"🟡 Yellow","wiki_hash":"sha256:b9d20a310ca48ffd858e6d0d4e49b5e0568ecb57dc5ad981eb54398562864691"},"tests/cache_and_artifacts.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:b9483666c1e19f90d4db1af718b08beebadfbcba66152497b7694d8e757a5ec1","status":"🟡 Yellow"},"tests/cli_surface.rs":{"last_updated":"2026-11-05 05:37:11","reason":"docs name the Cargo version (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:0aef6e3256a524e014971637bad8a928deba528b734995728bfb72ea606730f5","status":"🟡 Yellow"},"tests/contract_gaps.rs":{"last_updated":"2026-11-03 08:56:14","reason":"Tests for those parity fixes.","source_content_hash":"sha256:dc91a239bbc615524b4ac2c58d06515183dfc4981309906003f551e6721d82ae","status":"🟡 Yellow"},"tests/dogfood.rs":{"last_updated":"2026-11-05 06:20:17","reason":"wiki updated (claude/tool-groups)","source_content_hash":"sha256:36af6c04119986796434bcf75be9095cd2c28d7e0df476c72463343181c83328","source_mtime_ns":"1793859367674990400","status":"🟢 Green","verification":"verified","wiki_hash":"sha256:0bc5f3d78d1779ba6302ecc406dc0b25d8beda25f1681a26d57e97210df19906"},"tests/parity.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:0246038a1cc01bf66da2fd186ede61f2dcd2c98da9c0c90dd7f3b2cbab1036db","source_mtime_ns":"1793683314773282057","status":"🟡 Yellow","wiki_hash":"sha256:32753c244642df6e08f8578c6203f77225363783c15bc57c33a84f03989f2378"},"tests/parity_fixes.rs":{"last_updated":"2026-11-05 05:15:33","reason":"pending item wording and empty-queue note (claude/windows-verify speed)","source_content_hash":"sha256:b74f37dffb2a5bbcc8724298885a677a9d4476f846791d31770798e0a6caa7a3","status":"🟡 Yellow"},"tests/protocol_v07.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:bb7cffecabc3fb51ebcc77c64f7fd78f5cd15c445d7e13493ed491227280f37d","source_mtime_ns":"1793684781738827745","status":"🟡 Yellow","wiki_hash":"sha256:b38f4a13e316cefd56070f822980b4f83d9cdacb850ab1978de48ed35c630ec8"},"tests/robustness.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:fad304193a47baa8cce21cff8786b35974c7c7f6f71b3318edeb68bd60121681","status":"🟡 Yellow"},"tests/skip_maps.rs":{"last_updated":"2026-11-03 08:56:15","reason":"Tests for those parity fixes.","source_content_hash":"sha256:2eed0c6bc97d91a4be3f2b6ab08c78c62a3a05725a503496e3df91abad6b2130","status":"🟡 Yellow"},"tests/speed_paths.rs":{"last_updated":"2026-11-05 05:37:11","reason":"self-heal and durable user-state tests (claude/windows-verify release-5.1.0)","source_content_hash":"sha256:a9348e032c3ffd9f6960710b364470cbcbf935f366af604dd2ad62ac4f2a7a9e","status":"🟡 Yellow"},"tests/tool_groups.rs":{"last_updated":"2026-11-05 06:30:10","reason":"always advertise tools.listChanged; nested agent-tools examples are text; broken-pipe-safe test helper (claude/tool-groups listChanged)","source_content_hash":"sha256:4729ff17973c0fa5ebbf53730783753a04a7c87f0c30a3ab1f69adaac627c0a8","status":"🟡 Yellow"},"wikifier.sh":{"last_updated":"2026-11-03 08:06:46","reason":"Wiki describes the Rust binary launcher (subid=protocol-v07)","source_content_hash":"sha256:4f467e2117e8c361882054998cb0506717d9555e2aa570f0e176fc18d9c2f4aa","source_mtime_ns":"1793410024331635951","status":"🟢 Green","verification":"unchecked","wiki_hash":"sha256:3876708eaec60862b9b8b6f73e2ae87e4abca2f228c456f973ddb7c9ee36854a"}},"version":2} \ No newline at end of file diff --git a/file_health.md b/file_health.md index 0d02009..0131237 100644 --- a/file_health.md +++ b/file_health.md @@ -4,7 +4,7 @@ |------|--------|--------------|-----------------| | .github/workflows/publish.yml | 🟢 Green | 2026-11-03 09:27:04 | Multi-target release archives and SHA256SUMS (subid=release-5.0.0) | | AGENTS.md | 🟢 Green | 2026-11-05 06:26:37 | wiki updated (claude/tool-groups) | -| CHANGELOG.md | 🟢 Green | 2026-11-05 06:26:17 | wiki updated (claude/tool-groups) | +| CHANGELOG.md | 🟢 Green | 2026-11-05 06:30:10 | wiki updated (claude/tool-groups listChanged) | | CLAUDE.md | 🟢 Green | 2026-11-05 06:26:17 | wiki updated (claude/tool-groups) | | CONTRIBUTING.md | 🟢 Green | 2026-11-03 05:34:35 | Address the 3 Nov review findings (subid=review-2026-11-03) | | Cargo.lock | 🟢 Green | 2026-11-05 06:20:18 | wiki updated (claude/tool-groups) | @@ -14,7 +14,7 @@ | Findings/M5.1-cross-hardening-analysis.md | 🟢 Green | 2026-07-09 05:02:27 | kept; stale yellow cleared | | Findings/Milestones-Overview.md | 🟢 Green | 2026-07-09 05:02:27 | kept; stale yellow cleared | | Findings/p6_real_world_validation_report.md | 🟢 Green | 2026-07-09 05:02:27 | kept; stale yellow cleared | -| README.md | 🟢 Green | 2026-11-05 06:26:37 | wiki updated (claude/tool-groups) | +| README.md | 🟢 Green | 2026-11-05 06:30:10 | wiki updated (claude/tool-groups listChanged) | | docs/spec.md | 🟢 Green | 2026-11-03 08:00:11 | Name the Rust binary and protocol v0.7 in the living principles (subid=protocol-v07) | | scripts/benchmark_parity.sh | 🟡 Yellow | 2026-11-03 08:56:15 | Benchmark script and measured results. | | scripts/benchmark_results.md | 🟡 Yellow | 2026-11-03 08:56:15 | Benchmark script and measured results. | @@ -31,8 +31,8 @@ | src/low_conf.rs | 🟡 Yellow | 2026-11-03 08:56:15 | Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. | | src/main.rs | 🟡 Yellow | 2026-11-03 08:56:14 | Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. | | src/maps_out.rs | 🟢 Green | 2026-11-05 05:15:33 | wiki updated (claude/windows-verify speed) | -| src/mcp.rs | 🟢 Green | 2026-11-05 06:26:16 | wiki updated (claude/tool-groups) | -| src/mcp_groups.rs | 🟢 Green | 2026-11-05 06:26:16 | wiki updated (claude/tool-groups) | +| src/mcp.rs | 🟢 Green | 2026-11-05 06:30:10 | wiki updated (claude/tool-groups listChanged) | +| src/mcp_groups.rs | 🟢 Green | 2026-11-05 06:30:10 | wiki updated (claude/tool-groups listChanged) | | src/parse.rs | 🟢 Green | 2026-11-05 05:15:33 | wiki updated (claude/windows-verify speed) | | src/pending_line.rs | 🟢 Green | 2026-11-05 05:19:31 | wiki (claude/windows-verify pending) | | src/proc.rs | 🟡 Yellow | 2026-11-03 08:56:14 | Parity with the Python package: wiki lookup, symbols, daemon, init, flags, MCP, cycles, and low-confidence actions. | @@ -55,5 +55,5 @@ | tests/robustness.rs | 🟡 Yellow | 2026-11-03 08:56:15 | Tests for those parity fixes. | | tests/skip_maps.rs | 🟡 Yellow | 2026-11-03 08:56:15 | Tests for those parity fixes. | | tests/speed_paths.rs | 🟡 Yellow | 2026-11-05 05:37:11 | self-heal and durable user-state tests (claude/windows-verify release-5.1.0) | -| tests/tool_groups.rs | 🟡 Yellow | 2026-11-05 06:26:16 | agent-chosen tool groups from the AGENTS.md agent-tools block, list_changed on edits (claude/tool-groups) | +| tests/tool_groups.rs | 🟡 Yellow | 2026-11-05 06:30:10 | always advertise tools.listChanged; nested agent-tools examples are text; broken-pipe-safe test helper (claude/tool-groups listChanged) | | wikifier.sh | 🟢 Green | 2026-11-03 08:06:46 | Wiki describes the Rust binary launcher (subid=protocol-v07) | diff --git a/journal/2026/11/05.md b/journal/2026/11/05.md index 0e63710..98647c2 100644 --- a/journal/2026/11/05.md +++ b/journal/2026/11/05.md @@ -426,3 +426,23 @@ **File:** CLAUDE.md **Reason:** Choosing groups section; AGENTS.md agent-tools block (claude/tool-groups) +## [2026-11-05 06:30:10] record-change +**File:** src/mcp.rs +**Reason:** always advertise tools.listChanged; nested agent-tools examples are text; broken-pipe-safe test helper (claude/tool-groups listChanged) + +## [2026-11-05 06:30:10] record-change +**File:** src/mcp_groups.rs +**Reason:** always advertise tools.listChanged; nested agent-tools examples are text; broken-pipe-safe test helper (claude/tool-groups listChanged) + +## [2026-11-05 06:30:10] record-change +**File:** tests/tool_groups.rs +**Reason:** always advertise tools.listChanged; nested agent-tools examples are text; broken-pipe-safe test helper (claude/tool-groups listChanged) + +## [2026-11-05 06:30:10] record-change +**File:** README.md +**Reason:** always advertise tools.listChanged; nested agent-tools examples are text; broken-pipe-safe test helper (claude/tool-groups listChanged) + +## [2026-11-05 06:30:10] record-change +**File:** CHANGELOG.md +**Reason:** always advertise tools.listChanged; nested agent-tools examples are text; broken-pipe-safe test helper (claude/tool-groups listChanged) +