Inspiration

You sit down to watch something, scroll catalog rows across five streaming apps, and twenty minutes later you still have not picked. It is not a content problem. It is a choosing problem.

We wanted the opposite on the TV: one title at a time that gets closer to your taste with every press of the remote, and, when you would rather ask, a butler who knows your taste and answers out loud. FireDrift helps you pick, then hands you over to the app that streams the title. It complements streaming services; it does not compete with them.

What it does

FireDrift is a React Native for Vega app for Fire TV with two ways in, both driven by the remote.

The cover feed

  • One title at a time, full screen, with a slow animated backdrop, synopsis, rating and genres.
  • Right is Like, Left is Skip, Up/Down browse, OK is Watch now.
  • Every press, and the time you spend on a cover, changes your taste weights. The ranking is our own algorithm in AWS Lambda: the feed never calls an LLM, so it is fast and costs almost nothing.
  • Watch now shows which of your services stream the title (TMDB + JustWatch data) and opens that app.
  • You pick your services and country once. The feed shows only what you can watch.

The butler

  • An animated character, modeled, rigged and animated by us in Blender, with idle, listening, thinking and speaking states.
  • Press "Surprise me" or a chip, or hold to talk. He proposes one title, says why in his own voice (Amazon Polly), and offers the next replies as chips.
  • Ask for "something lighter" and he changes your taste weights live through a tool call, with Undo and Reset on screen.
  • Propose freely, TMDB confirms. The model proposes {title, year, type}; nothing reaches the screen unless TMDB resolves it. Every poster, synopsis, link and service comes from TMDB, never from the model text.
  • Polly speech marks time each gesture, so the character gestures on the right word.
  • If the agent, the voice or a spending cap fails, the butler falls back to chips backed by the ranking algorithm, and tries the agent again on the next visit. The feed is never affected.

Built for the TV

  • D-pad first: every screen works with the remote and shows focus.
  • One cover in memory at a time; the butler adds at most one clip player.
  • No account and no personal data: a random device ID, your country, your services and your signals. Voice audio is never stored.

How we built it

  • App: React Native for Vega (RN 0.83), TypeScript strict. A mock mode reads shared fixtures, so the app runs without a backend.
  • Backend: HTTP API Gateway, Lambda (TypeScript, ARM, Node.js 22) and DynamoDB on demand, with the TMDB data cached. One AWS CDK app deploys the whole stack, one construct per teammate.
  • Butler agent: a Strands agent in Python on Amazon Bedrock AgentCore Runtime, over a WebSocket. Model: Claude Haiku 4.5 on Bedrock, with Amazon Nova 2 Lite as a config fallback. AgentCore Gateway turns our Lambdas into tools (get_weights, update_weights, ranked_picks, resolve_titles, similar).
  • Voice: push to talk streams 16 kHz PCM to the agent, which sends it to Amazon Transcribe streaming. Answers come back as Amazon Polly neural speech with speech marks. Anonymous device sign-in with Amazon Cognito; the app holds no secret.
  • Cost by design: no NAT Gateway, no VPC Lambda, no always-on resource. The butler has per-session and daily caps and a kill switch in DynamoDB.
  • Contracts first: packages/domain holds zod schemas and fixtures for the REST API, the butler socket and the agent tools. The three of us built against them without waiting for each other.
  • Quality: typecheck, lint, Jest, pytest and a TV UI audit (focus and input) run on every pull request.
  • AI tools: we wrote code, tests and docs with Claude Code and reviewed and tested all of it. At run time only the butler uses AI models.

Challenges we ran into

  • No WebView on the Vega Virtual Device on Ubuntu and Intel Mac. Our first design was a trailer feed in a YouTube player. We moved to covers with an animated backdrop, which also fits the device memory better.
  • No audio input on the Vega Virtual Device. We could not record the microphone there, so we tested the agent end with a scripted client and made chips a full alternative to voice.
  • The clip player and the character. The player rejected file:// URLs with a bare MediaError; a plain /pkg/assets/... path plays and loops.
  • Claude Haiku 4.5 blocked on Bedrock after it had worked (use case form). We ran on Nova 2 Lite through one config value, then picked the model with a small eval on the demo prompts.
  • A model must not invent titles. "Propose freely, TMDB confirms" fixed it: the model can be creative, the screen stays true.
  • $150 of credits. Caps per turn, per session and per day, a kill switch, and a feed that never calls a model.
  • We logged every tool problem as a friction-log issue with steps and a suggestion (18 issues).

Accomplishments that we're proud of

  • The butler never shows an invented title. Every card comes from TMDB.
  • The AI changes your taste and you stay in control: validated, clamped tool calls with Undo.
  • The feed works without any AI, so the main screen has no model cost and no model latency.
  • Cheap to run: about $0.013 per butler turn on Claude Haiku 4.5 and $1.87 of total AWS spend from Oct 1 to Oct 21, before credits.
  • A character, not a chat box: our own Blender butler whose gestures land on the spoken word.
  • Three people, no blocking, thanks to shared schemas and fixtures.

What we learned

  • A contract-first split lets three people work in parallel and plug in the real service later.
  • A fallback path (chips) is cheaper and more robust than a perfect voice path.
  • A scripted model behind the Strands Model interface tests the whole agent loop and our real tools without Bedrock, and the same prompts on Bedrock give a cheap model comparison.
  • Streaming Transcribe from Python needs a SigV4-signed WebSocket; boto3 has no streaming client for it.
  • The Vega tools are young: keep a friction log from day one.

What's next for FireDrift

  • Test push to talk and the character on a Vega device, then measure memory.
  • Add the trailer player when the Vega WebView runs on our simulators.
  • Conversation mode: the butler listens again after it speaks.
  • Household profiles and a group mode.
  • Spanish UI and voice, then a Vega Appstore release.

Built With

Share this project:

Updates

Submission history