CLI-Anything Tigris Agent Harness 实战指南:基于官方 CLI 的 S3 兼容对象存储 Agent 化封装
【免费下载链接】CLI-Anything"CLI-Anything: Making ALL Software Agent-Native" -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything
本篇技术指南围绕仓库tigris/agent-harness/TIGRIS.md展开,系统讲解 CLI-Anything 项目如何将 Tigris(全球分布式、S3 兼容、免出口流量费的对象存储服务)的官方命令行工具封装为面向编码 Agent 的标准操作流程(SOP)工具包。读完本文,你将掌握该 Harness 的安装配置、七大类命令组(auth / bucket / object / presign / snapshot / access-key / iam)的完整用法、两种输出模式(人类可读与--json机器可读)的取舍,以及如何结合子进程封装、环境变量注入等源码机制,让 Claude Code、Codex 等 Agent 安全地管理快照、IAM、作用域访问密钥等 Tigris 原生能力。
设计定位:为什么是"包装 CLI"而不是"重写 S3 协议"
Tigris 是一个全球分布式、S3 兼容的对象存储服务,其显著特点是无出口流量费(no egress fees)。CLI-Anything 的 Tigris Harness 在设计上做出了一个关键决策:
直接包装官方
tigrisCLI,而不是用 Python 重新实现 S3 协议。
这一决策带来了两个直接收益(见 tigris/agent-harness/cli_anything/tigris/tigris_cli.py 与 utils/tigris_backend.py 的模块注释):
- Agent 能触达 Tigris 的全部原语:快照(snapshots)、IAM、作用域访问密钥(scoped access keys)、组织(organizations)、OAuth——这些是通用 S3 端点不具备的 Tigris 独有能力;
- 自动继承上游新命令:上游 CLI 发布新命令后,Harness 无需改动即可使用。
同时,TIGRIS.md 明确划定了使用边界:这是 Tigris CLI 专用工具,不要把它当作通用 S3 端点封装,也不要当作 MinIO、Cloudflare R2、AWS S3 或其他任意 S3 兼容端点的管理工具——它只会向官方tigris二进制发起子进程调用,并遵循该 CLI 的认证与命令模型。
从源码结构看,整个 Harness 的核心调用链是:click命令组(tigris_cli.py)→TigrisBackend(utils/tigris_backend.py)→subprocess.run(["tigris", ...])。setup.py的依赖声明中特意注明"no boto3"(见 setup.py),进一步印证了"零协议重实现、纯子进程封装"的架构取向。
环境要求与安装
TIGRIS.md 列出的前置条件如下:
Python 3.10+:代码使用 PEP 604 联合类型语法(如
str | None)与 PEP 585 泛型。macOS 系统自带 Python 为 3.9,需使用pyenv、uv或brew install python@3.12升级;tigrisCLI 必须在 PATH 上,二选一安装:npm install -g @tigrisdata/cli brew install tigrisdata/tap/tigris安装后执行一次
tigris login完成浏览器 OAuth 认证。
安装 Harness 本身则通过:
cd tigris/agent-harness pip install -e .[dev]安装后获得cli-anything-tigris控制台入口(见 setup.py 的entry_points配置),同时支持python -m cli_anything.tigris模块入口(见main.py)。
二进制可用性的优雅降级
TigrisBackend.init通过shutil.which(cli_path)解析二进制路径;若找不到,会抛出TigrisCliError并附带安装提示。而在 CLI 入口中,这个错误被延迟处理——ctx.obj["backend"]置为None,从而保证即使没有安装tigris二进制,--help依然可用(见 tigris_cli.py)。这是一个值得借鉴的 CLI 设计细节。
全局入口与命令行选项
Harness 的根命令cli是一个click分组,支持四个全局选项(见 tigris_cli.py):
| 选项 | 默认值 | 说明 |
|---|---|---|
--json | False | 以 JSON 格式输出(透传上游--format json) |
--cli-path | tigris | tigris二进制路径,二进制别名t3也可用 |
--access-key | None | 可选访问密钥 ID,导出到子进程环境变量 |
--secret-key | None | 可选秘密密钥,导出到子进程环境变量 |
调用方式:
cli-anything-tigris --json bucket list cli-anything-tigris object put --bucket my-bucket --key hello.txt --text "hello"此外入口还设置了auto_envvar_prefix="TIGRIS_CLI",意味着所有参数都可以通过TIGRIS_CLI_*前缀的环境变量注入。不带任何子命令启动时,会进入交互式 REPL,内置help/quit/exit命令,并提供一份完整的命令速查表(见 tigris_cli.py)。
后端原理:子进程封装与双环境变量认证
TigrisBackend._run 是整条链路的"发动机",其工作方式完全呼应 TIGRIS.md 的 Backend Description:
- 每条命令构建
tigris <args> --format json调用(--format json追加在末尾,避免与子命令解析冲突); - 通过
subprocess.run执行,默认check=True,非零退出码抛出TigrisCliError并携带 stderr 信息; json=True时解析 stdout 为 JSON;若上游命令不支持 JSON 输出(如login、cp),解析失败则回退为原始文本;capture=False时(如login)直接流式输出到调用方 TTY。
认证机制方面,默认情况下凭证由tigrisCLI 自身解析——即tigris login建立的 OAuth 会话。若显式传入--access-key/--secret-key,则会在子进程环境中同时注入四组变量(见 tigris_backend.py):
TIGRIS_STORAGE_ACCESS_KEY_ID / TIGRIS_STORAGE_SECRET_ACCESS_KEY AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY同时注入TIGRIS_STORAGE_*与AWS_*两组前缀,是为了兼容依赖环境变量认证的混合部署场景。大部分用户应优先使用tigris login。
路径归一化:t3://与tigris://
后端模块中的_path_to_t3工具函数统一将tigris://...、裸bucket/key、/bucket/key归一化为t3://...(见 tigris_backend.py),对应的单元测试在 tests/test_core.py 中覆盖了全部四种输入形态。对象层还提供了_parse_tigris_uri将 URI 拆解为(bucket, key)二元组并拒绝非法路径(见 core/object.py)。
七大命令组全解
1.auth:登录 / 登出 / 身份查询
包装tigris login/logout/whoami(见 core/auth.py):
cli-anything-tigris auth login # 浏览器 OAuth 登录,流式输出到终端 cli-anything-tigris auth logout cli-anything-tigris auth whoami # 打印当前用户 / 组织whoami在--json下输出带缩进的 JSON,否则以section/status的皮肤样式展示键值对。
2.bucket:存储桶生命周期管理
包装tigris buckets ...(见 core/bucket.py):
cli-anything-tigris bucket list cli-anything-tigris bucket create --name my-bucket cli-anything-tigris bucket delete --name my-bucket --yes # 必须显式 --yes cli-anything-tigris bucket info my-bucket # 即 tigris buckets get关键安全语义:delete命令在未传--yes时直接拒绝执行,输出错误并退出码 1(见 bucket.py)。列表与 info 输出会同时兼容小写(name/created)与首字母大写(Name/CreationDate)两种字段命名,以适配上游 CLI 的 JSON 结构差异。
3.object:对象读写与复制
包装tigris ls/cp/rm/stat(见 core/object.py):
# 列出(支持前缀过滤 + 客户端侧 limit 截断) cli-anything-tigris object list --bucket my-bucket [--prefix logs/] [--limit 100] # 上传:文件或内联文本二选一 cli-anything-tigris object put --bucket my-bucket --key data.json --file ./data.json cli-anything-tigris object put --bucket my-bucket --key note.txt --text "hello world" # 下载与删除 cli-anything-tigris object get --bucket my-bucket --key data.json --output ./out.json cli-anything-tigris object delete --bucket my-bucket --key data.json # 元数据(stat) cli-anything-tigris object info --bucket my-bucket --key data.json # 复制:本地↔t3 或 t3↔t3,支持 -r 递归 cli-anything-tigris object cp ./local.txt t3://my-bucket/remote.txt cli-anything-tigris object cp -r t3://src-bucket/dir/ t3://dst-bucket/dir/实现细节值得注意:
--file与--text必须且只能提供其一,否则退出码 2 并报错(见 object.py);- 内联文本上传通过
tempfile.NamedTemporaryFile落盘后走tigris cp,finally中清理临时文件(见 tigris_backend.py); cp命令要求 src/dst 至少一侧是t3://或tigris://URI,否则拒绝执行(见 object.py);- 对象删除实际调用
tigris rm ... --yes。
4.presign:预签名 URL
包装tigris presign(见 core/presign.py):
cli-anything-tigris presign get --bucket my-bucket --key data.json [--expires 3600] cli-anything-tigris presign put --bucket my-bucket --key upload.bin [--expires 3600] [--access-key KEY_ID]--expires默认 3600 秒,--access-key可选指定签名用的访问密钥 ID,默认自动解析;- 后端兼容两种上游返回形态:JSON 字典中的
url字段,或裸字符串 URL(见 tigris_backend.py); --json模式输出{"url": ..., "method": "GET", "expires_in": ...}信封。
Agent 场景价值:预签名 URL 可以把对象访问权"临时移交"给其他工具或下游 Agent,全程不共享任何凭证。
5.snapshot:存储桶快照
包装tigris snapshots list/take(见 core/snapshot.py)。快照是存储桶状态的时间点只读副本,属于 Tigris 独有、通用 S3 兼容厂商不提供的 Agent 存储原语:
cli-anything-tigris snapshot list my-bucket cli-anything-tigris snapshot take my-bucket [--name pre-migration]TIGRIS.md 的 Agent 使用规范建议:在破坏性操作之前先snapshot take建立恢复点,之后用snapshot list找到要恢复的快照。
6.access-key:作用域访问密钥
包装tigris access-keys(见 core/access_key.py),是 Harness 中最完整的命令组:
cli-anything-tigris access-key list cli-anything-tigris access-key create agent-run-42 # 密钥仅显示一次! cli-anything-tigris access-key get KEY_ID cli-anything-tigris access-key delete KEY_ID --yes # 必须 --yes cli-anything-tigris access-key assign KEY_ID --bucket my-bucket --role Editor cli-anything-tigris access-key rotate KEY_ID --yes # 必须 --yes源码中的安全细节:
create与rotate在人类可读模式下会明确提示"secret shown ONCE, save it now"(见 access_key.py);delete与rotate均设有--yes防线,未显式确认时拒绝调用后端(见 access_key.py);assign通过--bucket+--role(如Editor、Viewer)把密钥作用域收窄到单个桶,实现最小权限。
Agent 场景价值:每次 Agent 运行可以access-key create铸造一把临时作用域密钥 →assign限定桶与角色 → 任务结束delete撤销,做到"一次运行、一把密钥、用完即销"。
7.iam:策略与用户管理
包装tigris iam policies与tigris iam users(见 core/iam.py):
# 策略 cli-anything-tigris iam policy list cli-anything-tigris iam policy create my-policy --document ./policy.json # 用户 cli-anything-tigris iam user list cli-anything-tigris iam user invite someone@example.com [--role member]user invite的--role默认member。IAM 策略配合access-key assign,让 Agent / 组织可以向程序化客户端授予狭窄、可审计的权限(见 iam.py 模块注释)。
输出模式:人类可读与机器可读
TIGRIS.md 将输出模式分为两类:
- 人类可读(默认):通过
ReplSkin渲染表格、颜色与格式化文本。各命令组都做了字段名兼容(如桶列表同时识别name/Name、created/CreationDate),并将结果整理为 "Name / Created"、"Key / Size / Modified" 等表头; - 机器可读(
--json):透传上游 CLI 的--format json原始输出;对不支持 JSON 的原生命令(如cp),则包一层薄信封,例如{"src": ..., "dst": ..., "status": "copied"}。错误路径在--json下输出{"error": ...}结构。
REPL 皮肤来自仓库中未修改复用的ReplSkin(见 utils/repl_skin.py,对应 TIGRIS.md 架构图中的 "unified REPL skin")。
Agent 使用规范(SOP)
TIGRIS.md 为编码 Agent 总结了一套可直接落地的操作规范:
- 输出可解析:调用时传
--json; - 检查返回码:0 表示成功;
- 读 stderr:错误信息从 stderr 获取;
- 服务端复制:使用
object cp t3://src/key t3://dst/key做服务端拷贝——数据不流经 Agent,不产生出口流量费; - 预签名移交:用
presign get/put把对象访问权移交给其他工具或下游 Agent,不共享凭证; - 快照兜底:破坏性操作前
snapshot take建立恢复点,snapshot list查找恢复目标; - 临时密钥:
access-key create+access-key assign --bucket B --role Editor为单次 Agent 运行铸造作用域密钥,结束后access-key delete撤销; - 显式确认:桶删除、访问密钥删除、密钥轮换都必须显式传
--yes,否则 Harness 拒绝调用后端——这是 Harness 内置的最后一道安全闸门。
测试体系:从 Mock 单测到真实 E2E
TIGRIS.md 与 tests/TEST.md 共同定义了两层测试:
单元测试层(tests/test_core.py):
cd tigris/agent-harness pip install -e .[dev] pytest cli_anything/tigris/tests/test_core.py -vsubprocess.run被完全 Mock,模块加载时连shutil.which也被 patch,因此无需安装tigrisCLI、无需网络即可跑通,适合任何 CI 环境;- 覆盖范围包括:URI/路径归一化、二进制解析失败、凭证环境变量导出、七组命令的参数拼装、非零退出码抛
TigrisCliError、CLI 集成层的--json输出等。
端到端测试层(tests/test_full_e2e.py):默认跳过,需要三把"钥匙"同时满足:
npm install -g @tigrisdata/cli && tigris login export CLI_ANYTHING_TIGRIS_TEST_BUCKET=<your-test-bucket> export CLI_ANYTHING_TIGRIS_RUN_E2E=1 pytest cli_anything/tigris/tests/test_full_e2e.py -vE2E 覆盖whoami会话非空、测试桶存在、对象 put/get/head/list/delete 全链路回环、预签名 URL 格式正确且包含 key 末段、snapshots list成功等场景。每个测试用 per-run UUID 前缀避免多开发者 / CI 并发撞键,finally块兜底清理。
目录结构速览
TIGRIS.md 给出了完整的架构布局,仓库实际目录与之完全对应:
tigris/agent-harness/ ├── setup.py # cli, prompt-toolkit; 无 boto3 ├── TIGRIS.md # 本文档 └── cli_anything/tigris/ ├── __main__.py # python -m 入口 ├── tigris_cli.py # click CLI + REPL 分发器 ├── core/ # auth / bucket / object / presign / snapshot / access_key / iam ├── utils/ # tigris_backend.py(子进程封装)+ repl_skin.py(统一皮肤) ├── skills/SKILL.md # Agent 技能文档 └── tests/ # test_core.py(Mock 单测)+ test_full_e2e.py(环境门控 E2E)小结
CLI-Anything 的 Tigris Harness 用"包装官方 CLI、绝不重写协议"这一克制的架构选择,换来了全量原语覆盖 + 零维护升级 + OAuth 原生认证三大优势。对 Agent 开发者而言,它提供了一条把对象存储变成 Agent 原生能力的成熟路径:--json机器可读输出保证可解析性,--yes防线保证破坏性操作可控,快照 + 作用域密钥 + 预签名 URL 三件套则分别覆盖了"回滚、最小权限、凭证隔离"三大 Agent 存储安全诉求。结合 Mock 单测与真实 E2E 双测试体系,这套 Harness 可以放心地嵌入任何 Agent 工作流。
【免费下载链接】CLI-Anything"CLI-Anything: Making ALL Software Agent-Native" -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考