Metadata-Version: 2.5
Name: lekha-poth-cli
Version: 2.2.0
Summary: Production Typer CLI covering every Lekha Poth HTTP API endpoint.
Author: Hermes Agent
License: MIT
Requires-Python: >=3.12
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic-settings>=2.4.0
Requires-Dist: pydantic>=2.7.0
Requires-Dist: rich>=13.7.0
Requires-Dist: typer>=0.15.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# Lekha Poth CLI (`lp`) v2

Production Typer + Pydantic client for **every** Lekha Poth HTTP endpoint,
generated from `backend/src/app/api` on `main` (kept in sync — currently
140 routes as of product v0.16.2 / `6d2c833`; regenerate with
`generate_spec.py` after any route change, guarded in CI by
`backend/tests/unit/test_agent_spec_current.py`).

Replaces the old stdlib `scripts/agent/lp.py` reader CLI.

## Install

Published on PyPI as [`lekha-poth-cli`](https://pypi.org/project/lekha-poth-cli/).
No checkout needed:

```bash
uv tool install lekha-poth-cli      # → $HOME/.local/bin/lp
uv tool upgrade lekha-poth-cli      # later, to pick up new routes and flags
$HOME/.local/bin/lp --version
```

On macOS `/usr/bin/lp` is the print spooler and is on `PATH`, so call the
Lekha Poth CLI by its absolute path (`$HOME/.local/bin/lp`), or use the
alias entry point `lekha-poth`, which nothing else claims. To try it without
installing: `uvx --from lekha-poth-cli lp --help`.

An **agent skill** that teaches an LLM agent to drive this CLI ships in the
sdist under `skills/lp-cli/` (and in the repository at
`scripts/agent/lpcli/skills/lp-cli/`); its `README.md` says where to put it.

### Developing against a checkout

```bash
cd scripts/agent/lpcli
uv venv .venv && uv pip install --python .venv/bin/python -e ".[dev]"
.venv/bin/python -m lekha_poth_cli --version
# or, as a tool that tracks the working tree:  uv tool install -e .
```

### Releasing

**Actions → Release (lekha-poth-cli) → Run workflow** (`bump` minor by default,
or an exact `version`). It stamps every copy of the contract version
(`scripts/ci/stamp-lpcli-version.py`), runs the tests, `uv build`s, commits
and tags `lpcli-vX.Y.Z` on `main`, then `uv publish`es to PyPI. See
`docs/CICD.md` → "Releasing the agent CLI".

## Configure (once)

```bash
lp config set --api-base "$LEKHA_POTH_API_BASE" \
              --site-url "$LEKHA_POTH_SITE_URL" \
              --api-key lpak_…
# hosted production example:
#   --api-base https://api.lekhapoth.com/api/v1 --site-url https://lekhapoth.com
lp config set-defaults --output pretty --default-size 20
lp status
lp whoami
```

Config file: `~/.config/lekha-poth/config.json` (mode `0600`).
Existing keys (`api_base`, `api_key`, `site_url`, `key_name`, `created_at`) are kept.

Env overrides: `LEKHA_POTH_API_BASE`, `LEKHA_POTH_API_KEY`, `LEKHA_POTH_SITE_URL`, `LEKHA_POTH_CONFIG`.

## Coverage

```bash
lp endpoints              # every route, from endpoints.json
lp endpoints --admin
lp --help
lp admin items --help
lp items get --help       # every query/body field is a flag
```

Raw escape hatch:

```bash
lp api request GET /items --param size=5 --param kind=text
lp api request GET /health --root
```

Staff media (initiate → direct PUT → complete → poll):

```bash
lp upload ./ep.mp4 --visibility public --role original --item-id UUID --wait
```

## Iron rules (from the live API)

- Wire JSON is **camelCase** except pagination: `{size, next_cursor, has_next}` (never `hasNext`, no `total` on public lists).
- Errors: `{"error": {code, message, details, request_id}}` — branch on `error.code`.
- `coverUrl` is stable or `null`. `assets[].url` may be presigned (~15 min); match assets by `role`.
- Legacy `/chapters` and `/series` exist only when `APP_LEGACY_API_ENABLED`.
- Never store presigned URLs. Never put `lpak_` in git, skills, or Hermes memory.

## Regenerating the route catalogue

`src/lekha_poth_cli/endpoints.json` drives every command, and it is **derived
from the live FastAPI app** — there is no intermediate artefact to keep in sync:

```bash
cd backend
uv run python ../scripts/agent/lpcli/scripts/generate_spec.py          # rewrite it
uv run python ../scripts/agent/lpcli/scripts/generate_spec.py --check  # verify only
```

`--check` writes nothing and exits non-zero when the tracked file is stale.
`backend/tests/unit/test_agent_spec_current.py` runs the same comparison in CI,
so adding a route to the API without regenerating fails the build.

A **new** route stops the generator with an error rather than inventing a
command name for it: the id is what a person types, so it is a decision. Add an
entry to `NEW_IDENTITY` in the generator and re-run. Existing ids, `auth` values
and hand-shortened flag names (`--status` for the parameter `status_filter`) are
preserved on every run — they are the public CLI surface.

Regenerating covers the **routes**. `docs/agent/*`, `agent/SKILL.md`,
`public/llms.txt` and `public/.well-known/agent.json` are still updated by hand.
