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>
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
DefaultToolRegistryimplementsToolRegistryfromcore:tools.SandboxedToolExecutorwrapsDispatchingToolExecutor; 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).
ToolConfigis the only configuration surface; pass viaInfrastructureModule.createToolExecutor().buildTools()extension onToolConfigassembles the full tool list; add new tools there, not in the registry directly.file_copycopies one existing file to another path ({source, dest}) so static/binary assets never pass through the model's token stream. Same jail, anchor andfileWrite.enabledtoggle asfile_write; It declaresToolCapability.CONTENT_FROM_SOURCE(its bytes are a faithful copy ofsource), 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.destis the mutated target (ParamRole.PATH, the only affected path),sourceis read-only (ParamRole.SOURCE_PATH) and may sit under an operator-granted out-of-workspace path exactly as afile_readmay. 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_writeonly writes ({path, content}),file_editedits, andfile_deleteonly deletes ({path}) — deletion is a separately-named capability so a model can never delete by getting a write-mode parameter wrong.file_deletesharesfile_write's path jail andfileWrite.enabledtoggle and carriesToolCapability.FILE_WRITE. list_diris 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 implementingcore:toolscontracts:FileReadTool,FileWriteTool(write-only),FileDeleteTool,FileEditTool, list; no separate AGENTS.md (sub-leaf, covered by this doc)