skill_list shows what was discovered (name, source root, directory, description)
together with the copies a name collision shadowed and the notes from repaired
frontmatter, so a third-party skill never disappears quietly. skill_read
addresses a skill by name and defaults to its SKILL.md, reusing read_file for
ranges, line numbers, and the continuation token; a bundled file is resolved
inside the skill directory only, symlinks included. skill_search greps every
visible skill (or one) and rebases each hit on its skill, which makes a match
attributable without absolute paths.
Reads need no grant: the host registers the roots as static read-only roots on
the workspace policy, so read_file/grep_files see skill directories too while
write access stays denied — skill writes will go through their own confirm.
Grep used to drop every file outside the primary workspace root, which also hid
hits under a granted directory; those now come back as absolute paths.
New ToolTag.READ_ONLY marks tools that never mutate host state, plus
ToolRegistry.clone(read_only_only=True) to select just those (for safe
side turns / planning). Builtin read-only set: read_file, get_truncated,
glob_paths, grep_files, listdir, tree, todo_list, wait, ask_user_*,
vcs_* and fetch.
fetch is tagged READ_ONLY but can mutate via method; a new
read_only_context ContextVar makes it accept GET only while set.