Skip to content

feat(scripted_tool): add ScriptedTool for multi-tool bash composition#213

Merged
chaliy merged 8 commits intomainfrom
claude/scripted-tool-orchestration-Kv7BE
Feb 18, 2026
Merged

feat(scripted_tool): add ScriptedTool for multi-tool bash composition#213
chaliy merged 8 commits intomainfrom
claude/scripted-tool-orchestration-Kv7BE

Conversation

@chaliy
Copy link
Contributor

@chaliy chaliy commented Feb 18, 2026

Summary

Adds ScriptedTool, a new Tool implementation that lets LLMs orchestrate multiple sub-tools in a single bash script. Each registered tool becomes a builtin command, enabling composition via pipes, variables, loops, and conditionals without multiple round-trips.

Also removes the PydanticAI integration (unused) and reverts for-loop brace/glob expansion from #211 that was causing issues.

New: ScriptedTool module

New module crates/bashkit/src/scripted_tool/ gated by the scripted_tool feature flag:

  • ToolDef + ToolArgs: OpenAPI-style tool definitions with optional JSON Schema for input parameters and type coercion
  • Flag parsing: Converts --key value and --key=value CLI args into typed JSON objects per the tool's schema (integer, number, boolean, string)
  • ToolBuiltinAdapter: Wraps ToolCallback (Arc-based) as a Builtin, so tool callbacks can be invoked as bash commands
  • ScriptedToolBuilder: Fluent API to register tools with definitions + closures, set execution limits, and configure env vars
  • Tool trait impl: Provides introspection (help, system_prompt, schemas) and execution (single + status-callback variants)
  • 31 unit tests: Builder config, flag parsing, single/multi-step execution, pipelines, loops, conditionals, error handling, stdin piping
  • Example: crates/bashkit/examples/scripted_tool.rs — e-commerce API with get_user, list_orders, get_inventory, create_discount tools
  • Spec: specs/014-scripted-tool-orchestration.md

Design

  • Each execute() call creates a fresh Bash instance with all tool callbacks registered as builtins via Arc::clone
  • Type coercion follows JSON Schema property types declared in ToolDef.input_schema
  • System prompt generation includes tool descriptions, usage hints, and tips for LLM consumption
  • Standard bash utilities (echo, jq, grep, sed, awk, etc.) work alongside tool builtins

Removed: PydanticAI integration

  • Deleted crates/bashkit-python/bashkit/pydantic_ai.py and examples/pydantic_ai_bash_agent.py
  • Removed pydantic-ai optional dependency from pyproject.toml
  • Updated specs/013-python-package.md to reflect removal

Reverted: for-loop brace/glob expansion

Files changed

Area Files
ScriptedTool src/scripted_tool/{mod,execute}.rs, Cargo.toml, lib.rs
Example examples/scripted_tool.rs
Spec specs/014-scripted-tool-orchestration.md
PydanticAI removal bashkit-python/bashkit/{__init__,pydantic_ai}.py, pyproject.toml, examples/pydantic_ai_bash_agent.py
Interpreter revert src/interpreter/mod.rs, test spec cases
Docs AGENTS.md, specs/009-implementation-status.md, specs/013-python-package.md

Compose multiple CallableTools into a single Tool that accepts bash
scripts. Each CallableTool becomes a builtin command, so an LLM can
orchestrate N tools in one call using pipes, variables, loops, and jq.

- CallableTool trait: sync sub-tool interface (name, description, call)
- OrchestratorTool: implements Tool, creates fresh Bash per execute()
- Arc-based sharing: tools survive across multiple execute() calls
- OrchestratorToolBuilder: fluent API for configuration
- Auto-generated system_prompt/help with tool command docs
- 19 unit tests + doctests covering pipelines, loops, error handling
- Example: e-commerce API demo (get_user, list_orders, get_inventory)
- Spec: specs/014-scripted-tool-orchestration.md

https://claude.ai/code/session_01UcTwLqLrhbCFAuL26Fcm5W
…ack API

- Rename scripted_tool.rs → orchestrator/ module (mod.rs + execute.rs)
- Replace CallableTool trait with ToolDef (OpenAPI-style: name, description,
  input_schema) + closure callback — two arguments to builder.tool()
- Gate entire module behind `orchestrator` feature flag
- System prompt now renders input_schema when present
- Rename example to orchestrator.rs
- Update spec 014 and AGENTS.md

https://claude.ai/code/session_01UcTwLqLrhbCFAuL26Fcm5W
- Module: orchestrator/ → scripted_tool/
- Structs: OrchestratorTool → ScriptedTool, OrchestratorToolBuilder → ScriptedToolBuilder
- Feature flag: orchestrator → scripted_tool
- Example: orchestrator.rs → scripted_tool.rs
- Update spec 014

https://claude.ai/code/session_01UcTwLqLrhbCFAuL26Fcm5W
…lue flag parsing

Callbacks now receive ToolArgs {params, stdin} instead of (&[String], Option<&str>).
The adapter parses --key value / --key=value flags from bash args, coercing types
per the tool's input_schema (integer, number, boolean, string). ToolArgs provides
convenience accessors: param_str, param_i64, param_f64, param_bool.

https://claude.ai/code/session_01UcTwLqLrhbCFAuL26Fcm5W
Clippy disallows unwrap() even in test code. Replace all instances with
expect() providing descriptive panic messages.

https://claude.ai/code/session_01MARrisPkoUhn1L7j3rirwU
@chaliy chaliy changed the title Add ScriptedTool: compose multiple tools via bash scripts feat(scripted_tool): add ScriptedTool for multi-tool bash composition Feb 18, 2026
@chaliy chaliy merged commit ace5d14 into main Feb 18, 2026
15 checks passed
@chaliy chaliy deleted the claude/scripted-tool-orchestration-Kv7BE branch February 18, 2026 00:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants