Summary
Add ana api <service>/<method> — an authenticated raw-JSON verb that posts a body to any Connect-RPC endpoint on the configured profile and prints the response. Mirrors gh api.
Motivation
During issue #24 triage we needed to inspect chat history with a structure the existing CLI verbs don't surface (SQL cells nested inside message cells, full execError detail). Workaround was shelling to python3 + json.tool, which required understanding request shapes and reimplementing bearer auth out-of-band. This is a recurring pattern whenever:
- probing a newly-captured endpoint from
api-catalog/ before authoring a verb
- debugging a verb's wire shape (did the server change the field name?)
- reading fields the typed CLI verb doesn't render
- reproducing a server-side bug without waiting for a dialect-specific verb
gh api solves exactly this for GitHub. ana api should solve it for TextQL.
Shape
ana api <path> [--method GET|POST] [--data <json>|--data-stdin] [--raw] [--profile <p>]
<path>: either a full Connect-RPC path (textql.chat.v1.ChatService/GetChatHistory) or a service/method pair we complete against the service prefix registry that each verb package already declares.
--data / --data-stdin: request body (default {}).
- default output: pretty-printed JSON on stdout; non-zero exit + stderr on HTTP error.
--raw passes through exactly what the server returned (no prettify) for streaming endpoints.
- auth + endpoint + profile resolution: reuse the existing
--token-file/--profile/--endpoint globals — no new config.
Implementation sketch
Thin wrapper over transport.Client.Unary (already does authenticated JSON + error wrapping). New verb package internal/api/ registering a single leaf. No new Deps beyond Unary.
Out of scope
- Streaming RPCs (handle later with a separate
--stream flag).
- Request templating / variable substitution.
- Caching or replay.
Prior art
gh api (GitHub CLI) — same idea, same audience expectations.
curl + hand-rolled bearer — what we fall back to today.
Summary
Add
ana api <service>/<method>— an authenticated raw-JSON verb that posts a body to any Connect-RPC endpoint on the configured profile and prints the response. Mirrorsgh api.Motivation
During issue #24 triage we needed to inspect
chat historywith a structure the existing CLI verbs don't surface (SQL cells nested inside message cells, fullexecErrordetail). Workaround was shelling topython3+json.tool, which required understanding request shapes and reimplementing bearer auth out-of-band. This is a recurring pattern whenever:api-catalog/before authoring a verbgh apisolves exactly this for GitHub.ana apishould solve it for TextQL.Shape
<path>: either a full Connect-RPC path (textql.chat.v1.ChatService/GetChatHistory) or aservice/methodpair we complete against the service prefix registry that each verb package already declares.--data/--data-stdin: request body (default{}).--rawpasses through exactly what the server returned (no prettify) for streaming endpoints.--token-file/--profile/--endpointglobals — no new config.Implementation sketch
Thin wrapper over
transport.Client.Unary(already does authenticated JSON + error wrapping). New verb packageinternal/api/registering a single leaf. No new Deps beyondUnary.Out of scope
--streamflag).Prior art
gh api(GitHub CLI) — same idea, same audience expectations.curl+ hand-rolled bearer — what we fall back to today.