{"slug": "show-hn-verb-authority-per-argument-authority-checks-for-ai-tool-calls", "title": "Show HN: Verb Authority – per-argument authority checks for AI tool calls", "summary": "Verb Authority, a new open-source Python tool by yairsabag, enforces per-argument authority checks for AI tool calls, preventing untrusted data from authoring protected arguments like email recipients. The tool, available as version 0.10.0b14 on PyPI and GitHub, scans exported tool schemas to produce a reviewable authority map and a runtime gate that blocks calls before execution if a locked sink is supplied by untrusted data. It supports Python 3.10-3.14 and works with MCP, OpenAI, and Anthropic tool definitions, keeping schemas local and never invoking tools during scanning.", "body_md": "**Prevent untrusted data from authoring protected tool-call arguments.**\n\nConsider a tool exposed to an AI agent:\n\n```\nsend_email(to: str, body: str)\n```\n\nThe model may write `body`\n\n. The recipient `to`\n\nmust come from trusted\napplication code, such as an authenticated session or an application-owned\ndirectory. If a webpage, retrieved document, model response, or prior tool\nresult supplies a different recipient, the call must stop before\n`send_email`\n\nruns.\n\n**Tool schemas validate shape. They do not prove who may supply each value.**\n\nVerb Authority scans exported tool schemas, produces a reviewable per-argument authority map, and provides a small local runtime gate. It does not invoke tools while scanning and does not upload schemas.\n\nInstall the dependency-free core from PyPI:\n\n```\npython -m pip install \"verb-authority==0.10.0b14\"\n```\n\nOr install the same release tag directly from GitHub:\n\n```\npython -I -m pip install \"verb-authority @ git+https://github.com/yairsabag/verb-authority.git@v0.10.0-beta.14\"\n```\n\nThe dependency-free core supports Python 3.10 through 3.14. See\n[installation and package-integrity details](https://github.com/yairsabag/verb-authority/blob/main/docs/runtime-gate.md#install) for\nisolated-environment guidance, local checkout installation, wheel hashes, and\nthe optional Pydantic AI extra.\n\n```\npython -I -m verb_authority quickstart\n```\n\nThe command uses no model, network, or email service. It scans one exported schema and routes three local calls through the runtime boundary.\n\nExpected result excerpts:\n\n``` php\n1) SCAN THE EXPORTED TOOL SCHEMA\n   send_email.to    -> trusted_fixed\n   send_email.body  -> outbound_payload\n\n3) GATE RUNS IMMEDIATELY BEFORE EXECUTION\n   BLOCKED - param 'to' is a locked sink; data may not author it\n   local tool invocations=0\n\n4) THE SCHEMA LIMIT IS ALSO ENFORCED AT RUNTIME\n   body length=2001; registered maxLength=2000\n   BLOCKED - param 'body' failed its type/bounds check\n   local tool invocations=0\n\nALLOWED - within authority\nlocal tool invocations=1\n```\n\nThe demo implementation only increments an in-memory counter. It never sends email. In the allowed control, the recipient value is supplied independently by application code; the demo does not implement a human approval workflow.\n\nA provider typically gives every model-visible argument the same JSON Schema surface:\n\n```\n{\n  \"name\": \"send_email\",\n  \"inputSchema\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"to\": {\"type\": \"string\"},\n      \"body\": {\"type\": \"string\", \"maxLength\": 2000}\n    },\n    \"required\": [\"to\", \"body\"]\n  }\n}\n```\n\nBoth fields are strings, but they carry different authority:\n\n| Argument | Intended author | Example policy |\n|---|---|---|\n`to` |\ntrusted application code | `trusted_fixed` |\n`body` |\nmodel or other data source | `outbound_payload` |\n\nVerb Authority makes that distinction explicit and checks it immediately before execution.\n\nExport the `tools/list`\n\nJSON your client already receives. Then run:\n\n```\npython -I -m verb_authority scan tools.json --output authority-report.md\n```\n\nThe scanner accepts:\n\n- MCP\n`tools/list`\n\nresponses; - OpenAI function-tool definitions; and\n- Anthropic tool definitions.\n\nIt keeps the schema local, never starts the MCP server, and never invokes a tool. The report separates argument authority, review obligations, effective risk, advisory name signals, and author-supplied control evidence.\n\nFrom a repository checkout, try the frozen 23-tool Playwright MCP fixture:\n\n```\npython -I -m verb_authority scan fixtures/external/sankalp-gilda/playwright-browser-tabs/frozen/tools-list.json --format json --output authority-report.json\n```\n\nUse `--redact-names`\n\nbefore sharing a report, then still review the output.\nStable hashes and author-written evidence can remain correlatable or\ndictionary-guessable. See the full\n[scanner and report privacy contract](https://github.com/yairsabag/verb-authority/blob/main/docs/schema-scanner.md).\n\nIssue [#7: Real-schema clinic](https://github.com/yairsabag/verb-authority/issues/7)\nis the main feedback path. Report one missed lock, unnecessary lock, incorrect\nrisk tier, or wrong confirmation decision. A small redacted fixture is enough;\ndo not post secrets or private deployment data.\n\n`GuardedToolRunner`\n\nfreezes the registered tool and policy state, calls the\ngate immediately before the registered synchronous function, binds any\nconfirmation to the exact arguments and callable, and records successful\nplain-JSON results in one session ledger.\n\n``` python\nfrom verb_authority import GuardedToolRunner, Param, Registry, Risk, Tool\n\ndef send_email(to: str, body: str) -> dict:\n    # Trusted application implementation.\n    return {\"sent\": True, \"to\": to}\n\nregistry = Registry()\nregistry.add(\n    Tool(\n        \"send_email\",\n        [\n            Param(\"to\", \"email\", sink=True),\n            Param(\"body\", \"string\", max_len=2000, sink=False),\n        ],\n        fn=send_email,\n        risk=Risk.WRITE,\n    )\n)\n\nrunner = GuardedToolRunner(registry)\n\n# Read independently from authenticated application state—not model content.\nsession_recipient = \"alice@company.com\"\n\ntool_call = {\n    \"name\": \"send_email\",\n    \"input\": {\n        \"to\": session_recipient,\n        \"body\": \"Meeting summary\",\n    },\n}\n\nexecution = runner.run(\n    tool_call,\n    trusted_args={\"to\": session_recipient},\n)\nassert execution.executed, execution.decision.reason\n```\n\nNormalize provider-specific calls to the small\n`{\"name\": ..., \"input\": ...}`\n\nshape before dispatch. Every execution route\nmust pass through the runner. Risk tiers that require confirmation also need a\ntrusted synchronous `confirm`\n\ncallback. The surrounding application remains\nresponsible for authentication, business authorization, request freshness,\nrate limits, and external-state synchronization.\n\nRead the complete [runtime gate contract](https://github.com/yairsabag/verb-authority/blob/main/docs/runtime-gate.md) before a real\nintegration. It covers exact argument snapshots, confirmation binding, callable\nidentity, resource budgets, ledger saturation, error/no-retry behavior, trusted\ncatalog resolution, selector branches, and the pinned Pydantic AI adapter.\n\nBeta.14 includes an optional, narrowly pinned Pydantic AI adapter. It keeps\nprotected values out of the model-visible function or resolves model-visible\nkeys through an application-owned catalog before entering\n`GuardedToolRunner`\n\n.\n\n```\npython -m pip install \"verb-authority[pydantic]==0.10.0b14\"\n```\n\nThe adapter supports only the audited local, synchronous paths documented for\nthe pinned dependency versions. Unsupported remote, runtime-added, streaming,\nasync, realtime, and native execution paths fail closed. See\n[Pydantic AI 2.35 runtime adapter](https://github.com/yairsabag/verb-authority/blob/main/docs/runtime-gate.md#pydantic-ai-235-runtime-adapter).\n\nNo JavaScript/TypeScript runtime adapter is published in beta.14. JavaScript\napplications may export JSON schemas for an offline scan, but runtime\nenforcement must sit in a trusted server-side boundary rather than a browser\nbundle. See the [JavaScript and TypeScript evaluation path](https://github.com/yairsabag/verb-authority/blob/main/docs/javascript-typescript.md).\n\nCompare a protected baseline schema with the candidate schema:\n\n```\npython -I -m verb_authority diff tools-main.json tools-pr.json --fail-on-increase --fail-on-review\n```\n\nOr use the composite GitHub Action:\n\n```\n- uses: actions/checkout@v7\n- uses: actions/setup-python@v7\n  with:\n    python-version: \"3.12\"\n- uses: yairsabag/verb-authority@v0.10.0-beta.14\n  with:\n    before: tools-main.json\n    after: tools-pr.json\n    fail_on_increase: \"true\"\n    fail_on_review: \"true\"\n```\n\nThe baseline must come from a protected revision or trusted artifact, and the\ncandidate export must correspond to the implementation that will run. A diff\ndoes not authenticate either input or verify implementation behavior. See the\nfull [Authority Diff contract](https://github.com/yairsabag/verb-authority/blob/main/docs/schema-scanner.md#catch-authority-drift-between-versions).\n\n- The enforced claim is\n**per-argument provenance before execution**. - A schema scan infers a reviewable policy; it does not prove what an implementation does.\n- The gate does not classify prompts or prevent every prompt-injection effect.\n- It is not business authorization and does not validate arbitrary cross-argument, transaction, tenant, sequence, or purpose rules.\n- Untrusted content can still influence whether a tool is called or which member of an already trusted catalog is selected.\n- The optional ledger recognizes exact, contained, and selected lexical forms; it does not track arbitrary semantic rewrites.\n- The gate provides argument-integrity control, not confidentiality, secret tracking, or model-output filtering.\n- Any execution route that bypasses the gate is outside the guarantee.\n\nRead [Limits and boundaries](https://github.com/yairsabag/verb-authority/blob/main/docs/limits-and-boundaries.md) before using a\nreport or allowed decision as security evidence.\n\nThe scanner and core use conservative, reviewable defaults:\n\n- destination-like arguments such as recipients, URLs, accounts, paths, and\ncommands default to\n`trusted_fixed`\n\n; - free-text payloads such as bodies may be\n`outbound_payload`\n\n; - ambiguous arguments on consequential tools remain locked and require review;\n- type membership, an enum, or a numeric type does not by itself grant model authorship;\n- raw schema extensions cannot unlock an argument;\n- tool names are mutable advisory signals, not proof of runtime risk; and\n- undeclared or conflicting tool risk stays\n`unknown`\n\nand keeps confirmation enabled.\n\nTrusted registration code can resolve an overloaded argument with\n`Param(..., sink=True|False)`\n\n. A reviewed control sidecar can add implementation\nevidence to a scan, but the scanner labels that evidence as author-supplied\nrather than verified.\n\nFor exact selector branches, one trusted map can bind every value of one scalar enum selector to risk and active arguments. That map controls applicability and confirmation. It does not authorize the action instance or prove user intent.\n\nSee [Security model](https://github.com/yairsabag/verb-authority/blob/main/docs/security-model.md) for the complete model.\n\n[Security model](https://github.com/yairsabag/verb-authority/blob/main/docs/security-model.md)[Runtime gate and Pydantic AI adapter](https://github.com/yairsabag/verb-authority/blob/main/docs/runtime-gate.md)[JavaScript and TypeScript teams](https://github.com/yairsabag/verb-authority/blob/main/docs/javascript-typescript.md)[Schema scanner, control evidence, privacy, and Authority Diff](https://github.com/yairsabag/verb-authority/blob/main/docs/schema-scanner.md)[Limits and boundaries](https://github.com/yairsabag/verb-authority/blob/main/docs/limits-and-boundaries.md)[Case studies and executable evidence](https://github.com/yairsabag/verb-authority/blob/main/docs/case-studies/index.md)[Research landscape and citations](https://github.com/yairsabag/verb-authority/blob/main/LANDSCAPE.md)[Fixture contribution layout](https://github.com/yairsabag/verb-authority/blob/main/fixtures/README.md)[Security reporting](https://github.com/yairsabag/verb-authority/blob/main/SECURITY.md)[Changelog](https://github.com/yairsabag/verb-authority/blob/main/CHANGELOG.md)\n\nThe test suite covers inference, declared capabilities, tool risk, selector branches, dispatch, the guarded runner, confirmation binding, ledger containment, schema import, report redaction, Authority Diff, the Pydantic AI adapter, packaging, and frozen external regressions.\n\nPublic case material is preserved separately from CI reductions:\n\n[external risk-tier case study](https://github.com/yairsabag/verb-authority/blob/main/docs/case-studies/external-beta-risk-evidence.md);[frozen Playwright](https://github.com/yairsabag/verb-authority/blob/main/fixtures/external/sankalp-gilda/playwright-browser-tabs/README.md);`browser_tabs`\n\ncontribution[Tool Authority Atlas](https://github.com/yairsabag/verb-authority/blob/main/atlas/README.md), a small source-pinned corpus rather than a ranking of MCP servers; and[executable demos](https://github.com/yairsabag/verb-authority/blob/main/docs/case-studies/index.md#evidence-and-demos).\n\n`v0.9.0`\n\nis the latest stable release.\n`v0.10.0-beta.14`\n\nis the latest public prerelease and the first PyPI\ndistribution. Beta.14 makes the existing schema-to-gate behavior easier to\ninstall, evaluate, and integrate without changing the security promise or\npolicy-inference behavior. It retains the beta.13 offline quickstart and frozen\nexternal regression evidence. The beta.7, beta.8, and beta.9 identifiers were\nwithheld and will not be reused.\nThis remains early, research-grade work and is not described as\nproduction-ready.\n\nStart with one public or redacted schema fixture and one expected authority\nboundary. [CONTRIBUTING.md](https://github.com/yairsabag/verb-authority/blob/main/CONTRIBUTING.md) explains the fixture format,\nprovenance expectations, tests, and focused contribution process.\n\nFor sensitive vulnerabilities, do not open a public issue; follow\n[SECURITY.md](https://github.com/yairsabag/verb-authority/blob/main/SECURITY.md).\n\nFor real-schema product feedback, use\n[Issue #7](https://github.com/yairsabag/verb-authority/issues/7).\n\nLicensed under [Apache-2.0](https://github.com/yairsabag/verb-authority/blob/main/LICENSE).", "url": "https://wpnews.pro/news/show-hn-verb-authority-per-argument-authority-checks-for-ai-tool-calls", "canonical_source": "https://github.com/yairsabag/verb-authority", "published_at": "2026-09-01 06:17:14+00:00", "updated_at": "2026-09-01 06:52:27.369608+00:00", "lang": "en", "topics": ["ai-safety", "ai-tools", "developer-tools"], "entities": ["Verb Authority", "yairsabag", "PyPI", "GitHub", "MCP", "OpenAI", "Anthropic", "Playwright"], "alternates": {"html": "https://wpnews.pro/news/show-hn-verb-authority-per-argument-authority-checks-for-ai-tool-calls", "markdown": "https://wpnews.pro/news/show-hn-verb-authority-per-argument-authority-checks-for-ai-tool-calls.md", "text": "https://wpnews.pro/news/show-hn-verb-authority-per-argument-authority-checks-for-ai-tool-calls.txt", "jsonld": "https://wpnews.pro/news/show-hn-verb-authority-per-argument-authority-checks-for-ai-tool-calls.jsonld"}}