v0.3.0 — Agent-native CLI interface
Agent-native CLI interface. zot now serves humans, AI agents (Claude Code,
Codex), and orchestrators from a single surface. See docs/agent-interface.md
for the full contract.
Added
- Stable JSON envelope for every command:
{"ok": true, "data": ..., "meta": {...}}on success,{"ok": false, "error": {"code", "message", "retryable"}, "meta": {...}}on failure,{"ok": "partial", "data": {"succeeded", "failed"}}for batch operations. - TTY auto-detection:
--jsonis now implicit when stdout is not a TTY. Agents pipingzotoutput always get parseable JSON without remembering a flag. Override withZOT_FORMAT=json|table|text. - Typed exit codes: 0 success, 1 runtime error, 2 auth error, 3 validation error, 4 not-found, 5 network error, 6 conflict. Orchestrators can route failures deterministically.
zot schema [command...]— machine-readable introspection for the full CLI tree. Each entry carriesname,params(typed),safety_tier,since,deprecated, and nestedsubcommands. Agents can discover every command without a README.- Safety tiers in
--help: top-level help groups commands into Read / Write (MUTATES LIBRARY) / Destructive sections. Destructive command help carries a "MUTATES LIBRARY" warning. --dry-runon all mutating commands:add,update,note --add,attach,delete,trash restore. Preview shape:{"ok": true, "dry_run": true, "data": {"would": ...}}.--idempotency-keyonadd,update,note --add,attach,delete. SQLite-backed cache at$ZOT_CACHE_DIR/idempotency.db(default~/.cache/zotero-cli-cc) with 24h TTL. Retried calls carrying the same key return the original envelope and never duplicate the upstream mutation.metaslot on every envelope:request_id(uuid),latency_ms,schema_version,cli_version. Mutating commands also setsync_required: true.nexthints in success envelopes:add,update,delete,note --add,attachsuggest plausible follow-up commands so the agent saves a planning turn.retryablefield on every error: network / 5xx / rate-limit →retryable: true; not-found / validation / 4xx →retryable: false.ZoteroWriteErrorcarriescode,retryable,retry_after_seconds.--streammode onsearch,list,recent— emits NDJSON (one item per line) plus a summary line. Agents can process long result sets incrementally.- Structured stderr progress events for long-running commands (
add --from-file,summarize-all): NDJSON{event, phase, done, total, elapsed_ms, request_id}so agents can detect liveness without blocking on the final stdout envelope. - Confirmation-required guard on destructive commands:
zot delete K1with non-interactive stdin and no--yes/--dry-runreturns a structuredconfirmation_requirederror instead of blocking. - New
exit_codes.py,core/idempotency.pymodules. - 43 new tests across
test_agent_interface.py,test_agent_p1.py,test_agent_p2.py.
Changed
format_error/format_items/format_item_detail/format_collections/format_notes/format_duplicatesnow wrap JSON output in the envelope. Callers that parsed raw arrays must unwrap viaenv["data"].- Human error messages moved from stdout to stderr via the new
print_errorhelper. ErrorInfodataclass gainscodeandretryablefields.- Top-level CLI group uses a custom
TieredGrouphelp renderer.
Breaking
- JSON output contract: callers parsing bare arrays or dicts must now read from
env["data"]. Error responses now nest underenv["error"]withcode/message/retryablefields instead of a flat{"error": "..."}. - Exit codes: previously
1for all failures; now distinct codes per failure class. Scripts checking for any non-zero exit remain valid.