class LittleGhost::Tool

Give an agent a validated way to call application code. Every tool declares a model-visible name, description, and input shape before implementing its operation.

class TicketStatusTool < LittleGhost::Tool
  tool_name "ticket_status"
  description "Look up a support ticket's status."
  input_schema type: "object", properties: {
    ticket_id: {type: "string"}
  }, required: ["ticket_id"], additionalProperties: false

  def call(input)
    {ticket_id: input.fetch("ticket_id"), status: "waiting_on_customer"}
  end
end

result = TicketStatusTool.new.execute("ticket_id" => "SUP-481")
result.success?            # => true
JSON.parse(result.content) # => {"ticket_id"=>"SUP-481", "status"=>"waiting_on_customer"}

The class DSL produces the frozen specification sent to models. execute validates incoming arguments, invokes call, and normalizes strings, JSON-compatible collections, and other return values to model-facing text. Tool.define offers the same contract for an embedded implementation.

A tool registry creates one instance per agent run and supplies a Binding for access to the agent, run, runtime, model, workspace, and sandbox. Mutable per-instance state therefore belongs to that run. Registries close tools that implement close; exclusive true serializes calls against every other exclusive tool in the same run.

Validation and application ToolError failures become error results. A ToolError message is visible to the model and must be safe to disclose; unexpected exception messages are replaced with their class name. Cancellation, deadlines, and cleanup errors propagate instead of becoming ordinary tool output. The configured sandbox, not Tool itself, enforces filesystem and process isolation.