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 distributionotari-cli, import packageotari_cli, console commandotari). A command-line interface for the otari LLM gateway and platform. - The CLI is a thin shell over the
otariPython client SDK (source:mozilla-ai/otari-sdk-python). It does no HTTP of its own except thehealthcommand; everything else goes throughotari.OtariClientand 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 asotari_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)constructsotari.OtariClient. Command modules call it as_client.build_client(...)so tests can monkeypatch this single seam._context.py:AppContext(resolved config +--jsonflag) is built by the root callback and stored onctx.obj._errors.py:handle_errors()mapsotari.errors.OtariErrorsubclasses 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 aliasGATEWAY_PLATFORM_TOKEN): Bearer token;api_basedefaults tohttps://api.otari.ai. - Self-hosted (
GATEWAY_API_KEY+GATEWAY_API_BASE):Otari-Keyheader;api_baseis 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 annotationsat the top of modules;TYPE_CHECKINGfor type-only imports; importCallable/Iteratorfromcollections.abc.- mypy is
strict; new/changed code must be fully typed. - Prefer
str | NoneoverOptional[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
--jsonflag and routes failures throughhandle_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/, anduv run pytestbefore 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 like3โ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.