contract · Markdowncanonical

04 — Tools (vak-tools)

docs/design/04-tools.md
Raw
3.6 KB57 linesSnapshot ed4ab258

04 — Tools (vak-tools)

Status: implemented in 2.0.0

Contract

Tools never panic and never return Err. Every failure is a ToolOutput { content, is_error: true } the model reads and self-corrects. ToolContext carries cwd, cancellation child-token, output limits.

Built-ins

toolnotes
read1-based offset/limit paging, numbered lines, binary + image detection, continuation hint
writemkdir -p parents, full overwrite
editarray of {old_text,new_text}, sequential application, atomic (any failure ⇒ no write), uniqueness enforced, BOM preserved, CRLF detected & normalized for matching, unified diff in output
bashprocess-group spawn (setpgid), tree kill on timeout/cancel, stdout/stderr labeled + capped at 1MB each, exit code surfaced, non-zero ⇒ is_error
globglobset with literal_separator, ignores .git/node_modules/target
grepregex over text files, include-glob filter, match cap
webfetchGET-only bounded fetch (docs/design/29 P4): SSRF guard fail-closed pre-connect + per-redirect re-screen, ≤3 hops, 15s timeout, 512KiB cap, content-type filter, no credentials; classified network-capable ⇒ Ask outside FullAccess
browseheadless local Chrome-family --dump-dom (JS-rendered DOM) from inside the worker: browser discovery fail-closed (VAK_BROWSER override), same SSRF guard on the target, file-based DOM/stderr capture with closed-html sentinel, direct-pid SIGKILL (macOS re-exec), 20s deadline; same permission posture as webfetch
commitmentsread-only view of the durable commitments this agent holds (docs/design/47-commitment-kernel.md): what is open, what is blocked or waiting on a person, what evidence each still needs before it can close, and how the closed ones closed. Registered when [commitment] enabled, and part of the capability slice's orientation floor — an agent that cannot see its own obligations will re-open one. No write verb by design: the model may propose criteria and discuss a commitment, but the runtime evaluates satisfaction and the model never marks one passed (AGENTS.md invariant 33)

A capability rather than a gateway slash command on purpose. "What are you working on", "what is blocked", "did that ever finish" arrive on Telegram, the desktop and a cron check-in alike; a command layer would answer them on one transport and add a second dispatch path beside the tool broker. As a tool it reaches every surface, crosses the same permission boundary, and lands in the ledger like any other call.

Output hygiene

A tool returns its whole result and never shortens it; the only bounds are each tool's own capture limits (bash keeps 1 MiB, webfetch 512 KiB, read a line range). The agent loop records the whole result in the ledger and decides how much a request carries (vak_tools::window, docs/design/68-context-engine.md §3): up to 30,000 characters verbatim, and past that whole lines from the start and the end with one line naming the omitted range, its size, and the recall call that returns it. There is no spill file. A caller with no ledger (a flow node, a scheduled script) passes on vak_tools::bounded, the same window without the recall hint.

bash works in the workspace (or a cwd inside it), where the file tools work; temp files and caches go to .vak/scratch/<agent_id>/ (AGENTS.md invariant 35).

Unsafe policy

Exactly one unsafe block workspace-wide: process-group kill in bash.rs. Everything else is safe Rust.

Later

  • permission checks before execute (Phase 3)
  • LSP diagnostics tool (Phase 4+)
  • resource claims metadata per tool for fan-out scheduling (Phase 6)