Concepts
Platforms
What Upstream reads on GitHub, YouTube, Twitch and Kick, which id it binds to, and what can go wrong.
At a glance
| Id used | Proof text | Live status | |
|---|---|---|---|
| GitHub | repo:<id> or user:<id> | file .upstream on the default branch, or account bio | n/a |
| YouTube | channel id (UC...) | channel description | unknown |
| Twitch | numeric user id | channel bio | yes, with viewers |
| Kick | numeric user id | channel bio | yes, with viewers |
What you can type
Links, short links and bare handles with a prefix all work:
twitch.tv/name https://www.twitch.tv/name twitch:name
kick.com/name kick:name
youtube.com/@name youtube.com/channel/UCxxxxxxxxxxxxxxxxxxxxxx
github.com/owner/repo github.com/owner/repo.git github:owner
Names are validated against each platform's own rules before anything is fetched.
GitHub
Two kinds of target. A repo (owner/repo) is proven by a file named .upstream at its root on the default branch. Writing a file there needs write access, so it proves the person is a maintainer. An account (owner) is proven by the bio.
The engine reads api.github.com, which allows browser reads. Without a token GitHub allows 60 requests per hour per IP address; the engine reports rate_limited if you hit it.
pump.fun's own app already supports sending fees to GitHub accounts. Upstream adds repos and the same proof for the other three platforms.
YouTube
The code goes in the channel description. In a browser, YouTube blocks reads from other sites, so the page uses the official Data API with a key you restrict to your domain (put it in config.js). In Node, the CLI reads the public /about page and needs no key at all.
An id is a channel id (UC followed by 22 characters), found by the handle or given directly.
Twitch
The code goes in the channel bio. The engine reads the same public GraphQL endpoint the Twitch web player uses, with the handle passed as a variable (never pasted into the query text). It returns the numeric id, the bio, followers, and whether the channel is live now with its viewer count.
That endpoint is public and widely used, but Twitch has not promised to keep it. If it changes, Twitch reads will fail with a clear error until the adapter is updated. This is the most fragile of the four.
Kick
The code goes in the channel bio. The engine reads Kick's public channel endpoint, which returns the user id, bio, followers and the live stream if any. Kick sits behind a bot filter that sometimes refuses browsers; Node reads it reliably.
The live badge
Twitch and Kick tell us whether a channel is live. The app shows it next to the profile. It has no effect on money: it is information, and the vault never looks at it.
Adding a platform
An adapter is one function that takes a target and returns a profile: stable id, name, avatar, proof text, live state. Add it to src/engine/platforms.mjs, add tests with the platform's real response shape, and the rest (codes, attestations, the vault) works unchanged.