Metadata-Version: 2.4
Name: ai-agent-gateway-cli
Version: 0.6.0
Summary: Canonical dev CLI client for ai-agent-gateway
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: ai-agent-gateway==0.19.0
Requires-Dist: httpx>=0.28.1
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"
Requires-Dist: httpx>=0.28.1; extra == "dev"

# ai-agent-gateway-cli

Python client for the `ai-agent-gateway` HTTP/SSE protocol, shipped as the `hank`
entrypoint.

## Usage

```bash
python -m agent_gateway_cli login
python -m agent_gateway_cli chat "hello"
python -m agent_gateway_cli --config-namespace cashnerd login
python -m agent_gateway_cli --config-namespace cashnerd chat --session default "hello"
hank login
hank chat
hank chat "hello"
hank chat --model-key anthropic.claude-sonnet-5 --effort high \
  --model-key-for plan.author=anthropic.claude-opus-5 \
  --effort-for plan.author=high "research this company"
hank chat --model-key anthropic.claude-opus-5 --save-preference "remember this choice"
hank control health
```

The default config namespace is `agent-gateway` for `python -m agent_gateway_cli`
and `hank` for the `hank` entrypoint, which writes:

- `~/.cache/hank/cli_config.json`
- `~/.cache/hank/sessions/<name>.json`

`--config-namespace cashnerd` writes under `~/.cache/cashnerd/` instead. The
namespace directory and its `sessions/` directory are created mode 0700; the
files inside are 0600.

Each named session file holds a local transcript only. Conversation continuity
is held by the gateway session for about an hour and does not survive a gateway
restart; when it lapses, the CLI prints a notice and starts a new conversation.

`hank chat` with no message on an interactive terminal replaces the process with
the `agent-gateway-tui` binary (the Node >= 24 package
`@henrychien/agent-gateway-tui`), passing the resolved namespace and session as
arguments and the resolved connection as `GATEWAY_BASE_URL`, `GATEWAY_API_KEY`,
`GATEWAY_USER_ID`, and `AGENT_GATEWAY_ROUTE_PREFIX`. `hank chat "<message>"` and
any non-interactive stdout run the Python client in this package instead.

## Contract

The CLI sends `context.channel = "cli"` on every chat request. When `user_id`
is configured, it is sent as a top-level field on both `/api/chat/init` and
`/api/chat`. Tool approvals post `tool_call_id`, `nonce`, `approved`, and
`allow_tool_type`.

The CLI consumes authenticated `capability_choices` from `/api/chat/init`.
`--model-key` accepts only an exact session-eligible stable key, and `--effort`
requires it. When both are omitted, the chat request omits all selection fields
and the server resolves the capability default. Repeatable
`--model-key-for CAPABILITY=MODEL_KEY` and optional
`--effort-for CAPABILITY=LEVEL` flags populate strict init-time run overrides.
Provider-qualified selectors, upstream model names, display-label aliases, and
local fallback catalogs are not accepted.

`--save-preference` and `--clear-preference` use the authenticated server
preference contract for account-wide `session.driver` state. Local transcript
files do not store or resolve model preferences.

Every gateway request is composed as `base_url + route_prefix + path`, so the
hosted deployment is reached as `https://hank.investments/gateway/api/chat/init`.
The default `BaseUrlPolicy` accepts any hostname over `https`, allows `http`
only for a loopback host, and rejects a query or fragment. A base URL may carry
the deployment path: it is hoisted out of the base URL into the route prefix, so
`--base-url https://hank.investments/gateway` resolves to base URL
`https://hank.investments` with route prefix `/gateway/api`, identical to
`--base-url https://hank.investments --route-prefix /gateway/api`. An explicit
`--route-prefix` (or `AGENT_GATEWAY_ROUTE_PREFIX`) that neither equals nor
extends the base URL path is refused, naming both values. TLS
verification is on by default; `--insecure` and `HANK_INSECURE=1` are honored
only for a loopback gateway, and `HANK_CA_BUNDLE` selects a custom CA bundle.
Products that need a narrower policy can inject
`BaseUrlPolicy(allowed_schemes=..., allowed_hostnames=...)`.

## Control plane

Chat and control use separate credentials and separate channels. `hank login
--control-api-key <key> [--control-channel <channel>]` stores the control key in
the same namespace config file. Chat requests always send
`context.channel = "cli"`; control sessions default to `--control-channel tui`
(cron/scripts convention sets `AGENT_CONTROL_CHANNEL=cli` instead). Whichever
channel is used MUST match the channel of the `GATEWAY_USER_KEYS` entry the
control key belongs to, or session mint fails with `ChannelMismatch`.

`hank control <subcommand>` drives `/api/control/*`: `dispatch` starts an
autonomous run (`--profile analyst --mode once|skill … [--follow]`); `runs`,
`run`, `logs`, `watch`, `cancel` observe and steer it; `approvals`/`approve`/
`deny`, `batches`, `artifacts`, and `schedules` cover the rest. Run listings are
owner-and-channel scoped: `hank control runs` shows only runs started on the
control key's channel (documented in `docs/reference/agent-run-evaluation.md`).
