AGENTS.md

June 10, 2026 ยท View on GitHub

Guidance for agentic coding tools working in this repository. Scope: entire repo.

CLAUDE.md is a symlink to this file. Always edit AGENTS.md directly; never modify CLAUDE.md.

Project Snapshot

  • Project: otari-cli (PyPI distribution otari-cli, import package otari_cli, console command otari). A command-line interface for the otari LLM gateway and platform.
  • The CLI is a thin shell over the otari Python client SDK (source: mozilla-ai/otari-sdk-python). It does no HTTP of its own except the health command; everything else goes through otari.OtariClient and its control-plane resources.
  • Language/runtime: Python 3.11+ (CI matrix: 3.11, 3.12, 3.13).
  • Package manager + task runner: uv.
  • Source root: src/otari_cli (imported as otari_cli).
  • Tests: tests/unit (offline, the SDK client is faked).

Architecture (Big Picture)

  • config.py: OtariConfig.resolve(...) turns CLI flags + environment variables into resolved connection settings, mirroring the SDK's auth resolution (platform vs self-hosted; control-plane admin credential).
  • _client.py: build_client(config) constructs otari.OtariClient. Command modules call it as _client.build_client(...) so tests can monkeypatch this single seam.
  • _context.py: AppContext (resolved config + --json flag) is built by the root callback and stored on ctx.obj.
  • _errors.py: handle_errors() maps otari.errors.OtariError subclasses to clean stderr messages and stable process exit codes.
  • _output.py: Rich tables / text for humans, JSON for machines (--json).
  • commands/: one module per command. Generation commands (completion, models, health) register as functions; control-plane groups (keys, usage) are Typer sub-apps.
  • cli.py: the root Typer app; defines global options and wires the commands.

Two auth modes (must both keep working)

  • Platform (OTARI_AI_TOKEN, legacy alias GATEWAY_PLATFORM_TOKEN): Bearer token; api_base defaults to https://api.otari.ai.
  • Self-hosted (GATEWAY_API_KEY + GATEWAY_API_BASE): Otari-Key header; api_base is required.
  • Control plane (keys, usage, and future management commands) needs an admin credential (GATEWAY_ADMIN_KEY, or the platform token) and a self-hosted / standalone gateway.

Command Surface

Generation: completion, message, response (each with --stream), embedding, moderation, rerank, models. Batches: batches (create/retrieve/list/cancel/results); create reads a JSONL file of {custom_id, body} requests. Control plane: keys, users, budgets, pricing (CRUD), plus usage list and users usage. Diagnostics: health.

Control-plane create/update commands map the SDK's small request models (CreateKeyRequest, CreateUserRequest, etc.) to typed flags; --metadata takes a JSON object. New commands should follow the same shape: build the request via _client.session(...), route failures through handle_errors(), and honor the global --json flag.

Open polish items (tracked on the issue): curated table columns for the control-plane list commands, and an auth story for health if a gateway gates the endpoint.

Setup Commands

  • Install (dev): uv sync --extra dev

Test Commands

  • Full suite: uv run pytest
  • Single test: uv run pytest tests/unit/test_cli.py::TestCompletion::test_basic -v

Lint / Typecheck / Build Commands

  • Lint: uv run ruff check .
  • Typecheck (mypy strict): uv run mypy src/
  • Build: uv build

Repository Conventions

  • from __future__ import annotations at the top of modules; TYPE_CHECKING for type-only imports; import Callable/Iterator from collections.abc.
  • mypy is strict; new/changed code must be fully typed.
  • Prefer str | None over Optional[str].
  • Command modules call the client via _client.build_client(...) (not a re-imported name) so the test seam stays effective.
  • Every command honors the global --json flag and routes failures through handle_errors() for consistent exit codes.
  • Test classes are Test<Feature>; tests run offline against a fake client.

Change Validation Checklist

  • Run uv run ruff check ., uv run mypy src/, and uv run pytest before opening a PR. All must pass.

Writing style

  • Avoid em dashes and double hyphens (--) used as separators in prose (README, docs, doc comments, commit messages, PR descriptions). Use commas, semicolons, colons, parentheses, or periods, or rephrase. This does not apply to code (for example CLI flags like --all) or en-dash numeric ranges like 3โ€“4.

Notes for Agents

  • Prefer minimal, targeted edits; match existing typing and import style in touched files.
  • Preserve security-relevant behavior (credential resolution, error-detail boundaries). Never print resolved tokens or keys.