Skip to content

Rebuild twitch-cli on the kit framework - #1

Merged
tamnd merged 5 commits into
mainfrom
implement-twitch
Jun 14, 2026
Merged

Rebuild twitch-cli on the kit framework#1
tamnd merged 5 commits into
mainfrom
implement-twitch

Conversation

@tamnd

@tamnd tamnd commented Jun 14, 2026

Copy link
Copy Markdown
Owner

This rebuilds the twitch CLI from the first-pass cobra/fang scaffold onto the any-cli/kit framework, so every read command is declared once and drives the CLI subcommand, the HTTP route, and the MCP tool from a single source.

What it does

A single pure-Go binary that reads public Twitch the way a logged-out browser does, talking to Twitch's public GraphQL endpoint with the web client's public id. No API key, no login, nothing to run alongside it.

Command surface:

twitch streams                  top live streams right now
twitch games                    the category directory, by viewers
twitch search channels <query>  channels matching a query
twitch search games <query>     categories matching a query
twitch channel show <login>     a channel's metadata
twitch channel videos <login>   a channel's past videos
twitch channel clips <login>    a channel's clips
twitch channel schedule <login> a channel's upcoming schedule
twitch game show <slug>         a category's metadata
twitch game streams <slug>      live streams in a category
twitch game clips <slug>        top clips in a category
twitch video <id>               one video by id
twitch clip <slug>              one clip by slug
twitch ref id <ref>             classify a reference, offline
twitch ref url <kind> <id>      build a canonical URL, offline
twitch serve / twitch mcp       the same ops over HTTP and MCP

Access boundary

Twitch's public GraphQL answers a logged-out reader from any network, home or datacenter, so there is no IP soft-wall. The edge is the account line: anonymous access cannot reach following, chat, subscriptions, watch history, or per-viewer state. Records carry only fields that access can fill, so there are no always-empty columns. Exit 3 means a resource is genuinely empty, not that the network withheld it.

Layout

  • twitch/ the library: GraphQL client, queries, records, and domain.go (the kit driver)
  • cli/ assembles the kit App from the twitch domain
  • cmd/twitch/ thin main: hands cli.NewApp to kit.Run
  • docs/ the tago documentation site

Verification

gofmt, go vet, and go test ./... are clean; make build produces bin/twitch. The httptest-backed tests cover pagination, limit capping, the not-found/rate-limit/blocked paths, and reference classification. Every command was run live against Twitch and returns data anonymously from this network.

tamnd added 5 commits June 15, 2026 00:27
Replace the first-pass scaffold with a GraphQL client against Twitch's
public endpoint and a kit domain that declares every read once. Each
operation maps a typed input to a record stream, so the same declaration
drives the CLI, the HTTP server, and the MCP tool.

The client paces, retries, and caches requests by query hash, and walks
Relay cursor connections to honor --limit. Records carry only fields a
logged-out reader can fill: streams, channels, videos, clips, the
category directory, schedules, and search over channels and categories.
The domain also classifies and locates twitch:// references offline.
NewApp now builds the kit App from the twitch domain and folds the
domain-global flags (--client-id, --user-agent, --cache-ttl, --refresh)
into the config the client reads. The thin main hands NewApp to kit.Run
so the exit code carries the operation result.

Remove the hand-rolled streams command, the output helper, and the pkg
renderer; the kit output layer covers all of them.
Rewrite the README and docs site for the rebuilt surface: streams, the
category directory, a channel with its videos, clips, and schedule, a
single video or clip, search, and the offline ref tools. The honesty
note states the boundary plainly: Twitch's public GraphQL answers a
logged-out reader from any network, so the edge is the account line, not
an IP wall, and exit 3 means a resource is genuinely empty.

Add guides for collecting data, resource URIs, and adding a command.
Twitch sometimes answers a logged-out request with a "failed integrity
check" GraphQL error. It is a transient throttle, not a missing entity,
so map it to the rate-limited sentinel: the existing retry loop reattempts
it, and if it persists the exit code points the operator at pacing rather
than failing with an opaque message.
Model the README on the fleet's house style: lead with a command and the
table it actually prints, then cover why, install, quick start, how it
works, the access boundary with its exit-code table, the command list,
output formats, recipes, serve, and the resource-URI driver. Note that
output is colorized on a terminal and drops to plain text in a pipe, with
--color to force either way. Give the docs site a real description.
@tamnd
tamnd merged commit 0b07844 into main Jun 14, 2026
7 checks passed
@tamnd
tamnd deleted the implement-twitch branch June 14, 2026 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant