Skip to content

qargi 0.2.11

Choose a tag to compare

@github-actions github-actions released this 11 Nov 12:24
· 264 commits to master since this release

Added

  • qargi tool import SOURCE --tool-list FILE and qargi tool seal NAME --tool-list FILE judge the tools of a tool pack by the server's own tool listing: FILE is the JSON result of the server's MCP tools/list (or the response that holds it as result), saved to a file; qargi reads the file and never contacts a server. A tool that the listing does not annotate readOnlyHint: true, or does not name, may not be always_allow or auto unless the pack sets "write_ok": true; a tool annotated destructiveHint: true and a tool the listing does not name are reported in the review as NOTE lines; the check of the tool's name still applies. The pack's record keeps the sha256 of the listing and what it says of each tool of the pack (tool_list: read-only, write or destructive per tool; qargi tool show NAME prints it). tool_list is part of the content hash and of the plan token, so it is approved with the pack and a change of it is drift; a pack without one hashes as before. A later seal without the option keeps the record's listing, and a tool added to the pack since then counts as not listed. A file that is no listing ends the verb with exit 1, and the option with any other verb is a usage error (exit 2). Without a listing the review is the name check alone, as before.

Fixed

  • The review of a tool pack finds a write-like tool however the MCP server spells its name. The check only saw a write word at the start of a name or after _, so platform.delete_knowledge, repo/push, issue-close and deleteItem passed as always_allow or auto without write_ok. A name is now cut into words at every character that is not a letter (_, ., -, /, digits) and at a camelCase boundary (deleteItem, HTTPPost), and a word that starts with a write word (create, update, delete, remove, post, push, write, merge, send, set, add, edit, close, comment) makes the tool write-like, also in a name with no separator (deleteall, sendmail). A write word in the middle or at the end of a word does not count (offset, dataset), and the words settings, setting, address, addresses, postal, postcode, postcodes, additional and closest are taken for the names of things that are read, so settings_view, address_list and postal_code_lookup, which the old check refused, pass. The rule is written once, in lib/packs_check.py, and every review asks it (tool import, seal, show, link, check, the renders). A pack in your library that has such a tool unattended now fails qargi tool check and is not rendered until the tool is always_ask or the pack sets "write_ok": true, and you seal it again.
  • qargi packs apply --target claude-code PROJECT writes the permission rule of a tool under the name Claude Code gives the tool: mcp__SERVER__TOOL with every character of a name other than a letter, a digit, _ and - written as _, so the tool platform.list_items of the pack kb gets the rule mcp__kb__platform_list_items. The rule held the name as the pack writes it, which matched no tool when the name had a dot, and a name with a slash was refused. How a runtime writes a name is data of its definition (resources.mcp.name_key in lib/providers/schema-2.json: nonword-underscore, or absent for a name left as written; a runtime without it still takes only plain names). Two tools that would get the same rule (a.b and a_b of one server) are refused by the plan, since a rule for one would hold for the other. A render that holds a tool pack with a dotted name differs from what packs check now expects: apply it again.
  • The review of a tool pack checks the names in its tools map: letters, digits and _ . - /, 1 to 128 characters, the first a letter, a digit or _, so the dotted and slashed names that servers publish are accepted and a name with a blank, a control character, a quote or a wildcard fails with the name written as a JSON string. A tool pack that is not one JSON object, or whose tools is not an object (a list), fails its review; both passed before, because the check ended in an error and said nothing. The name of the pack keeps its rule (lower-case letters, digits, -).
  • A member's calls of MCP tools pass its guard, and a member has the MCP tools of its roles' tool packs and no others. The hook of a member matched Bash, Monitor, Edit, Write, NotebookEdit, Read and Grep, and the member definition listed no MCP tool: a call of an MCP tool was not judged, so a read-only (review) run that reached a tool pack could have called a write tool. The hook matcher now also covers mcp__.*, and the guard judges a call by the policy the tool packs of the role give that tool. It refuses a tool that is in no tool pack linked to the role, in every run; a tool whose pack is missing, changed since its approval or fails its review; an always_ask tool, since a member runs unattended; a name that stands for two tools of the role; and, in a read-only run, every tool that is not a declared read (always_allow, a name that is not write-like and, where the pack was approved with the server's tool listing, readOnlyHint: true). The role is the one of the run, as the lead's registry of local runs records it; the run is found from the member mark of qargi local run or from the directory of the call. qargi agent add and agent refresh write into a member's tool list the tools of the packs that reach its roles, under the names the runtime gives them (mcp__kb__platform_list_items), without the always_ask ones and, for a member of read-only roles alone, the declared reads only. The hook command of such a member names its project and roles (qargi __guard --project P --roles build,review), because an MCP call names no path and a member a session starts works outside its run directory: a call made where no run is found must be allowed for every one of those roles, each held to its class, and with neither a run nor those names the call is refused. Every member is STALE after this release, since the hook matcher changed, and again whenever a link, an unlink or a seal changes the tool packs of its roles: qargi agent refresh NAME --project P renders it. A runtime other than Claude Code is judged by the names its definition gives (resources.mcp.permission_rule and name_key), and one that gives none has no MCP calls to judge.