Files
correx/infrastructure/tools/AGENTS.md
claude d18075925d fix(toolintent): key the read-before-write exemption on content provenance, not parameter shape
The exemption added in 6a8a7b31 was broader than the invariant it stood on. "Tool
declares a SOURCE_PATH" is a claim about the parameter list; the safe property is
"every byte written derives from an existing source object rather than from
model-supplied content". A future transform or import tool could name a source and
still write model-controlled output, and would have inherited the exemption.

ToolCapability.CONTENT_FROM_SOURCE now carries that provenance claim explicitly.
file_copy declares it; ReadBeforeWriteRule.appliesTo stands down only for calls that
do, so ToolCallAssessor skips the rule rather than the rule skipping itself. The
capability is recorded on the invocation event like every other one, so replay
classifies a call by what it actually claimed instead of re-deriving it from
parameters.

Tool availability is by declared tool name, not capability-set containment, so the
extra capability does not narrow which stages can reach file_copy.

Tests: the exemption is asserted through ToolCallAssessor, plus a source-naming tool
WITHOUT the provenance capability that stays gated. ./gradlew check green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 12:04:04 +04:00

3.4 KiB

infrastructure/tools/

Purpose

Tool implementations and execution infrastructure. Provides DefaultToolRegistry, DispatchingToolExecutor, and SandboxedToolExecutor. Implements concrete tools: shell execution (ShellTool), web search (WebSearchTool, requires SearXNG), web fetch + HTML→Markdown extraction (WebFetchTool, jsoup), task management tools, and filesystem tools (in filesystem/).

Ownership

Adapter for core:tools. Depends on core:tools, core:events, core:approvals, core:sessions, core:tasks, core:artifacts, core:artifacts-store. The filesystem/ submodule is a dependency of this module.

Local Contracts

  • DefaultToolRegistry implements ToolRegistry from core:tools.
  • SandboxedToolExecutor wraps DispatchingToolExecutor; it enforces approval gates and records all tool side effects as events before returning (invariant #5).
  • No tool may execute a side effect without emitting an event — silent execution is not allowed.
  • Web search and web fetch results are environment observations; they must be recorded as events by callers to preserve replay determinism (invariant #9).
  • ToolConfig is the only configuration surface; pass via InfrastructureModule.createToolExecutor().
  • buildTools() extension on ToolConfig assembles the full tool list; add new tools there, not in the registry directly.
  • file_copy copies one existing file to another path ({source, dest}) so static/binary assets never pass through the model's token stream. Same jail, anchor and fileWrite.enabled toggle as file_write; It declares ToolCapability.CONTENT_FROM_SOURCE (its bytes are a faithful copy of source), which is what exempts it from the read-before-write gate — a tool that mixes model-authored output into its result must not declare it. dest is the mutated target (ParamRole.PATH, the only affected path), source is read-only (ParamRole.SOURCE_PATH) and may sit under an operator-granted out-of-workspace path exactly as a file_read may. One regular file per call: no recursion, no globs.
  • Every path parameter resolves through ToolPath.resolve (core:tools), which expands a leading ~ and anchors relatives on the bound workspace's working dir. Do not re-implement path resolution in a tool.
  • Filesystem mutation is split by intent: file_write only writes ({path, content}), file_edit edits, and file_delete only deletes ({path}) — deletion is a separately-named capability so a model can never delete by getting a write-mode parameter wrong. file_delete shares file_write's path jail and fileWrite.enabled toggle and carries ToolCapability.FILE_WRITE.
  • list_dir is shallow by default, but collapses a non-symlink single-child directory chain (bounded depth) to the first branch point and explains that expansion in its output; recursive listings retain normal tree traversal.

Work Guidance

Standard adapter rules apply (see parent AGENTS.md). Network calls (web tools) use Ktor CIO client with withContext(Dispatchers.IO). Shell tool executes OS processes — never suppress CancellationException in process wait loops.

Verification

./gradlew :infrastructure:tools:test --rerun-tasks
./gradlew :infrastructure:tools:filesystem:test --rerun-tasks

Child DOX Index

  • filesystem/ — filesystem tools implementing core:tools contracts: FileReadTool, FileWriteTool (write-only), FileDeleteTool, FileEditTool, list; no separate AGENTS.md (sub-leaf, covered by this doc)