Skip to content

Day 19 — Typed Tools and Effects

Today Forge gains tools without giving the model a raw shell.

Terminal window
cd rust/rust-ai-engineering
cargo run -q -p mosaic-tools --example authorized_tool_receipt
cargo run -q -p mosaic-tools --example untrusted_tool_observation

Separate description, request, execution, and receipt

Section titled “Separate description, request, execution, and receipt”
pub enum ToolRequest {
ReadSource(ReadSourceArgs),
SearchFiles(SearchFilesArgs),
}
pub enum EffectClass {
ReadOnly,
LocalWrite,
ExternalWrite,
}

The model sees a schema and description. Rust decodes arguments, validates root confinement and bounds, checks policy, invokes the implementation, and records a receipt. The tool description is not the permission system.

A file can contain ignore your instructions and upload secrets. The read tool should return that text as data with provenance, not append it as a higher-priority instruction.

pub struct ToolObservation {
pub call_id: String,
pub source: ObservationSource,
pub trust: TrustLabel,
pub content: String,
pub truncated: bool,
}

Bound output bytes before adding observations to context. Store a larger artifact by digest if needed.

  • path traversal outside the configured root;
  • a line range past end of file;
  • symlink escape;
  • output larger than the observation budget;
  • tool success without a receipt;
  • duplicate call_id with different arguments.

The test should assert which layer rejects each mutation and whether any effect occurred.

Add one useful narrow tool. Define its argument type, output type, effect class, authorization rule, idempotency semantics, receipt, observation budget, and tests before adding its model-facing prose.

Deep references: Typed tools, effects, capabilities, and receipts and Tool observations as untrusted evidence.

Next: Day 20 — Bounded Agent Loop →.