Tool Contract
July 31, 2026 · View on GitHub
Status
Implemented
Summary
bashkit follows the Everruns toolkit library contract from
everruns/specs/toolkit-library-contract.md.
Public shape:
ToolBuilder (config) -> Tool (metadata) -> ToolExecution (single-use runtime)
BashToolBuilder is the primary builder. ScriptedToolBuilder and
ScriptingToolSetBuilder mirror the same contract for orchestration tools.
Feature gating
The entire tool layer (tool module: Tool trait, BashTool*,
ToolExecution, ToolService, schema/OpenAI helpers) is gated behind the
bash_tool feature, which is on by default. Building with
--no-default-features drops the module and its exclusive dependencies
(tower, futures-core), leaving just the embeddable Bash interpreter.
scripted_toolbuilds on this layer and so enablesbash_tool.- Consumers that only drive
Bashdirectly (e.g.bashkit-cli) setdefault-features = falseto avoid pulling in the tool dependencies.
Public API
Tool trait, builders, ToolExecution, ToolOutput, ToolOutputChunk,
ToolError: see crates/bashkit/src/tool.rs / rustdoc.
Builder rules
build()is non-consuming.build_service()returnstower::Service<Value, Response = Value, Error = ToolError>.build_tool_definition()emits OpenAI-compatible function JSON.build_input_schema()/build_output_schema()match the built tool metadata.
Tool metadata rules
description()is token-efficient, one sentence, locale-aware.system_prompt()is terse plain text that starts with the tool name.help()is Markdown, not man-page text.execution()validates JSON args before returning a runnable execution.- Legacy
execute()/execute_with_status()stay available as convenience helpers.
Tool execution rules
ToolExecutionis single-use.output_stream()must be called beforeexecute().- Final truth is
ToolOutput, not concatenated streamed chunks. imagesis empty for bashkit today.
Error rules
ToolError::{UserFacing, Internal}:
UserFacingis safe for LLMs and localized.Internalis for logs/diagnostics and stays English.ToolError::is_user_facing()drives consumer mapping.
BashTool specifics
name():bashkit;display_name(): localizedBash/Баш
Input schema
{
"type": "object",
"properties": {
"commands": { "type": "string" },
"timeout_ms": { "type": ["integer", "null"] }
},
"required": ["commands"]
}
Output schema
ToolOutput::result matches:
{
"stdout": "string",
"stderr": "string",
"exit_code": 0,
"error": "string|null"
}
Streaming
BashTool::execution(...).output_stream() emits chunks with kind = "stdout"
or kind = "stderr"; chunk data is JSON string content.
Metadata
ToolOutput.metadata.extra currently includes { "exit_code": 0 }.
Scripted tool specifics
ScriptedToolBuilder and ScriptingToolSetBuilder follow the same contract:
locale-aware metadata, OpenAI tool definition helpers, tower::Service helper,
ToolExecution runtime path. ScriptedTool keeps help and discover
builtins for runtime schema discovery.
Locale
Localized strings implemented for en-US and uk-UA. Unsupported locales fall
back to English.
Locale affects: display_name(), description(), help(), system_prompt(),
ToolError::UserFacing.
Locale does not affect: name(), JSON property names and schemas, version().
Verification
Contract enforced by unit tests: builder helpers, OpenAI tool definition output,
tower::Service execution, JSON-arg validation via execution(), streamed
chunks, locale-aware metadata.
See also
- Scripted Tool Orchestration — composing tool definitions into scripted orchestrators
- Script Analysis — pre-execution introspection for host permission gating
- Bashkit Architecture — interpreter this contract exposes
- HTTP Transport — host-controlled egress reachable from tool scripts
- Known Limitations — behavior the contract deliberately does not promise