工具
 ](https://pypi.org/project/tooli/)  
Python的代理原生CLI框架。 编写一个函数,获得一个CLI、一个MCP工具和一个自文档模式。
Tooli将键入的Python函数转换为CLI命令,这些命令同时对人类友好(富输出、shell补全)和机器可消费(JSON模式、结构化输出、MCP兼容性)。您的工具不需要单独的“代理版本”。
名称来源于“tool”+“CLI”=“tooli”。
______________________________________________________________________
问题
AI代理每天调用数千个CLI命令,但标准CLI是为人类设计的:
- 交互式提示挂起代理 无法导航寻呼机或密码对话框
- 非结构化输出浪费代币 --代理使用正则表达式解析文本,而不是读取JSON
- 模糊的错误会妨碍自我纠正 --“错误:无效输入”使代理无法使用
- 无法发现 --特工们对无证工具产生了幻觉
Tooli将CLI视为 结构化协议 而不是文本界面。一个经过修饰的函数生成一个CLI命令、一个JSON模式、一个MCP工具定义、带有恢复建议的结构化错误和自动生成的文档——所有这些都来自一个单一的事实来源。
______________________________________________________________________
当前状态(v6.6.0)
Tooli v6.6.0已准备就绪,并发布于 PyPI该框架实现了其PRD中定义的完整功能集,并在Python 3.10+上扩展了测试套件。
今天有什么船
| 类别 | 功能 |
|---|---|
| 输出 | 双模式(TTY为富模式,代理为JSON/JSONL模式),自动检测。标准信封: {ok, result, meta} |
| 错误 | 类型化层次结构(InputError, AuthError, StateError, ToolRuntimeError, InternalError)有结构化的建议和恢复剧本 |
| 模式 | 来自类型提示的JSON模式,与MCP兼容 inputSchema 以及OpenAI函数调用。 $ref 取消引用以实现广泛的客户端兼容性 |
| 主控程序 | 通过stdio、HTTP或SSE将任何Tooli应用程序作为MCP工具服务器提供服务,无需额外代码。自动注册 skill:// 资源 |
| 输入 | StdinOr[T] 统一文件、URL和管道stdin。 SecretInput[T] 具有自动编辑功能 |
| 编排 | 隐藏 orchestrate run 确定性多工具计划执行命令(JSON / python 有效载荷) |
| 安全 | 行为注释(ReadOnly, Destructive, Idempotent, OpenWorld), @dry_run_support、安全策略(关闭/标准/严格)、身份验证范围 |
| 文档 | 面向任务的SKILL.md、增强的CLAUDE.md、llms.txt、Unix手册页——始终与代码同步 |
| 文档工具 | 使用外部 tooli-docs 从app/schema输入生成SKILL.md、CLAUDE.md和AGENTS.md |
| 构图 | 通过JSON/JSONL合约和编排计划进行模式优先组合 |
| 脚手架 | 使用 cookiecutter gh:weisberg/tooli-template 用于项目引导 |
| 分页 | 基于光标 --limit, --cursor, --fields, --filter |
| 呼叫者检测 | TOOLI_CALLER 用于代理识别的约定、5类启发式检测, detect-context 内置命令,信封/遥测/记录中的呼叫者元数据 |
| 可观测性 | 选择遥测,eval工作流的调用记录,OpenTetry具有调用者属性 |
| 评估 | 元数据覆盖报告器、升级分析器、LLM驱动的技能往返评估 |
| 可扩展性 | 提供者系统(本地、文件系统)、转换管道(命名空间、可见性)、工具版本控制 |
| Python API | app.call(), app.acall(), app.stream(), app.astream() 用于带类型的直接进程内调用 TooliResult 物体 |
| 能力 | 精细的权限声明(fs:read, net:write)通过严格模式执行 TOOLI_ALLOWED_CAPABILITIES |
| 多Agent | 代理工作流编排的交接元数据和委托提示。用于GitHub Copilot/Codex兼容性的AGENTS.md生成器 |
| HTTP API | OpenAPI 3.1模式生成+Starlette服务器(实验) |
______________________________________________________________________
安装
pip install tooli可选附加功能:
pip install tooli[mcp] # MCP server support (fastmcp)
pip install tooli[api] # HTTP API server (starlette, uvicorn) -- experimental______________________________________________________________________
快速开始
from tooli import Tooli, Annotated, Option, Argument
from tooli.annotations import ReadOnly, Idempotent
from pathlib import Path
app = Tooli(
name="file-tools",
description="File manipulation utilities",
version="6.6.0",
)
@app.command(
annotations=ReadOnly | Idempotent,
examples=[
{"args": ["--pattern", "*.py", "--root", "/project"],
"description": "Find all Python files in a project"},
],
)
def find_files(
pattern: Annotated[str, Argument(help="Glob pattern to match files")],
root: Annotated[Path, Option(help="Root directory to search from")] = Path("."),
max_depth: Annotated[int, Option(help="Maximum directory depth")] = 10,
) -> list[dict]:
"""Find files matching a glob pattern in a directory tree."""
results = []
for path in root.rglob(pattern):
results.append({"path": str(path), "size": path.stat().st_size})
return results
if __name__ == "__main__":
app()人类使用
$ file-tools find-files "*.py" --root ./src
┌──────────────────────┬───────┐
│ Path │ Size │
├──────────────────────┼───────┤
│ src/main.py │ 1,204 │
│ src/utils.py │ 892 │
└──────────────────────┴───────┘代理使用
$ file-tools find-files "*.py" --root ./src --json
{
"ok": true,
"result": [
{"path": "src/main.py", "size": 1204},
{"path": "src/utils.py", "size": 892}
],
"meta": {"tool": "file-tools.find-files", "version": "6.6.0", "duration_ms": 34}
}架构导出
$ file-tools find-files --schema
{
"name": "find-files",
"description": "Find files matching a glob pattern in a directory tree.",
"inputSchema": {
"type": "object",
"properties": {
"pattern": {"type": "string", "description": "Glob pattern to match files"},
"root": {"type": "string", "default": ".", "description": "Root directory to search from"},
"max_depth": {"type": "integer", "default": 10, "description": "Maximum directory depth"}
},
"required": ["pattern"]
},
"annotations": {"readOnlyHint": true, "idempotentHint": true}
}MCP服务器模式
$ file-tools mcp serve --transport stdio
$ file-tools mcp serve --transport http --host 127.0.0.1 --port 8080
$ file-tools mcp serve --transport sse --host 127.0.0.1 --port 8080添加到MCP客户端配置中,每个命令都会变成一个工具。
______________________________________________________________________
结构化错误
当出现问题时,代理会收到可操作的恢复指导,而不是不透明的消息:
$ file-tools find-files "*.rs" --root ./src --json
{
"ok": false,
"error": {
"code": "E3001",
"category": "state",
"message": "No files matched pattern '*.rs' in ./src",
"suggestion": {
"action": "retry_with_modified_input",
"fix": "The directory contains .py files. Try pattern '*.py' instead.",
"example": "find-files '*.py' --root ./src"
},
"is_retryable": true
}
}______________________________________________________________________
输出模式
Tooli会自动检测正确的输出格式,也可以显式检测:
| 标志 | 行为 |
|---|---|
| *(TTY,无标志)* | 为人类提供丰富的格式输出 |
--json | 单个JSON信封到stdout |
--jsonl | 用于流式传输的换行JSON |
--plain | grep/awk管道的未格式化文本 |
--quiet | 抑制非必要输出 |
______________________________________________________________________
输入统一
这 StdinOr[T] type使文件、URL和管道数据可互换:
from tooli import StdinOr
@app.command()
def process(
input_data: Annotated[StdinOr[Path], Argument(help="Input file, URL, or stdin")],
) -> dict:
"""Process data from any input source."""
...# All equivalent:
$ file-tools process data.csv
$ file-tools process https://example.com/data.csv
$ cat data.csv | file-tools process -______________________________________________________________________
试运行计划
执行前预览副作用:
from tooli import dry_run_support, record_dry_action
@app.command(annotations=Destructive)
@dry_run_support
def deploy(target: str) -> dict:
record_dry_action("upload", target, details={"size": "12MB"})
record_dry_action("restart", f"{target}-service")
# ... actual deployment logic$ file-tools deploy production --dry-run --json
{
"ok": true,
"result": [
{"action": "upload", "target": "production", "details": {"size": "12MB"}},
{"action": "restart", "target": "production-service"}
],
"meta": {"dry_run": true}
}______________________________________________________________________
自动生成的文档
# Agent-readable skill documentation (external package)
$ tooli-docs skill examples/docq/app.py:app --output SKILL.md
$ tooli-docs claude-md examples/docq/app.py:app --output CLAUDE.md
$ tooli-docs agents-md examples/docq/app.py:app --output AGENTS.md
# Framework wrappers (external package)
$ tooli-export openai examples/docq/app.py:app --mode import > tools_openai.py
$ tooli-export langchain examples/docq/app.py:app --mode import > tools_langchain.py
# LLM-friendly docs (llms.txt standard)
$ file-tools docs llms
# Unix man page
$ file-tools docs man有用的验证和自动化流程:
- 使用
--schema对于严格的指挥合同。 - 使用
tooli-docs ... --from-schema schema.json对于模式驱动的文档。 - 围绕信封形状使用CI断言(
ok/result/meta)以及错误代码。
迁移指南:请参阅 MIGRATION_v5_to_v6.md (v5至v6)。旧指南存档于 docs/archive/migration/.
______________________________________________________________________
全球旗帜
每个Tooli命令都会自动获得:
--output, -o auto|json|jsonl|text|plain
--json/--jsonl Convenience aliases
--quiet, -q Suppress non-essential output
--verbose, -v Increase verbosity (-vvv)
--dry-run Preview without executing
--yes Skip confirmation prompts (for automation/agents)
--no-color Disable colors (also respects NO_COLOR)
--print0 Emit NUL-separated output for list types in text/plain modes
--timeout Max execution time in seconds
--null Parse NUL-delimited list input from stdin (list-processing)
--schema Print JSON Schema and exit
--response-format concise|detailed
--help-agent Token-optimized help for agents______________________________________________________________________
建筑
Tooli构建在Python类型+装饰器管道的基础上,添加了一个并行模式生成路径:
@app.command()
Python function + type hints
| |
v v
CLI Pipeline Schema Pipeline
-> CLI params -> Pydantic model
-> CLI parser -> JSON Schema
| |
v v
CLI Output Agent Output
Rich tables MCP tool schema
Completions SKILL.md / JSON关键设计决策:
- 库-第一个API --公共界面是Tooli原生的(没有框架对象泄露到用户代码中)
- Pydantic模式 --与FastAPI和FastMCP相同的管道
- 函数保持可调用性 --无突变;测试与
CliRunner或者直接用Python调用
______________________________________________________________________
示例
这 examples/ 目录包含18个使用Tooli构建的完整CLI应用程序,每个应用程序都展示了不同的功能:
| 应用程序 | 功能 |
|---|---|
| docq | 只读、分页、stdin输入、输出格式 |
| gitsum | ReadOnly、subprocess、StdinOr用于差异 |
| Csvkit t | StdinOr,JSONL输出,分页,OpenWorld |
| 系统监视 | 只读、分页、结构化错误 |
| 任务者 | 一次性、破坏性、分页CRUD |
| 项目 | 破坏性、DryRun记录器、智能型 |
| 发送 | SecretInput、AuthContext作用域 |
| imgsort | 破坏性+临时性,DryRun记录器,批量操作 |
| note_indexer | 只读、分页、JSON索引、错误处理 |
请参阅 示例README 查看18个应用程序的完整列表和使用指南。
______________________________________________________________________
版本历史
- v6.6.0 (当前)--错误修复版本:CLI崩溃
T | None参数、恢复的触发器/反触发程序/规则元数据(#202、#203)。 - v6.5.0版本 --v6发布线,包括核心清理、提取跟进和可靠性改进。
- v6.0 --提取和清理释放。文档和导出生成转移到外部包(
tooli-docs,tooli-export);拆下了弃用的内部垫片。 - v5.0 --通用代理工具接口。添加了Python API、功能、切换元数据和AGENTS.md生成。
- v4.1 --呼叫者感知代理运行时。
TOOLI_CALLER常规、5类启发式检测,detect-context内置、信封/遥测/录音中的呼叫者元数据、自适应确认和帮助格式化。 - v4.0 --Agent Skill Platform基础和模式优先工作流。
- v2.0 --代理环境接口。MCP桥、编排运行时、延迟发现、令牌预算、Python eval模式。
- v1.0 --核心框架。双模输出、结构化错误、JSON模式、MCP服务器、注释、分页、可观察性。
看 更改日志.md 了解完整细节和 docs/MIGRATION_v5_to_v6.md 了解最新的升级步骤。
______________________________________________________________________
发展
# Clone and install for development
git clone https://github.com/weisberg/tooli.git
cd tooli
pip install -e ".[dev]"
# Run tests
pytest
# Lint and type check
ruff check .
mypy tooli看 贡献.md 作为指导方针。
许可证
MIT许可证。看 许可证 了解详情。
