Public: anyone can read this; the crew can change it.

The home page is the feed: server-rendered, live, on phone and desk #368

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`/` now shows the ranked feed to a signed-in viewer, but the `choose` deck card and the card's stop action are not built. The new feed tests and the existing studio, live, web and hardening suites pass. `tsc --noEmit` could not run here (the `bun` type definitions are missing), so the type check in `forge.json` is untested.

shipped production is serving it deploy d5b2fe2

opened this

/ now shows the ranked feed to a signed-in viewer, but the choose deck card and the card's stop action are not built. The new feed tests and the existing studio, live, web and hardening suites pass. tsc --noEmit could not run here (the bun type definitions are missing), so the type check in forge.json is untested.

What changed

  • First paint: the first 20 feed items render as cards above the apps shelf, server-side. The shelf and the "On you" rail stay as they were. Each card shows its one-sentence reason as a link into the thing.
  • Live refresh: /live/feed returns the feed region alone, with an etag and 304 on no change. The existing live-regions client refreshes it from /events using the same mechanism as the shelf; no new client plumbing.
  • Card actions:

- Run cards have a Steer form that posts to the run's existing steer route. - Every other card has Tell the crew, which posts to the app's existing tell route. - Dismiss and Mute app post to /api/v1/feed/interactions. - Opening a card is recorded as an opened interaction.

  • Keys: j/k/Enter are the shell's existing row navigation, and each card is a data-nav row. x dismisses the focused card.
  • Layout: one column on a phone, with larger tap targets. On a desk the feed takes the main column beside the rail.
  • Code: the page is src/web/studio/feed.ts, the card CSS is src/web/studio/feed_style.ts, and docs/FEED.md has a section on the page. There are no new dependencies. test/feed-page.test.ts is added to the check in forge.json.

Tests (test/feed-page.test.ts)

  • first paint matches the feed order
  • a hostile reason and a hostile app name are escaped
  • the card actions point at the right routes
  • a private app does not show up for another viewer
  • the fragment returns 304 on a repeat and 404 when signed out
  • a cross-origin dismiss is refused with 403
  • a same-origin dismiss removes the card from the next render

What I left out

  • choose card and swipe deck: nothing in the feed produces a choose item and there is no deck in the repo. That wants its own issue, with the swipe recorded as a swiped interaction.
  • Stop from a card: the feed currently only has finished runs, so a stop button would have nothing to stop. Steering a finished run is meaningful: it lands on the conversation and a run starts from it.
  • More than the first 20 items: there is no "more" control yet; the API's cursor already supports it.
  • Dismiss and mute without JS: these need a script. Tell and steer work as plain forms.

To try it: sign in and open /. Press j/k to move between cards, x to dismiss one, or open Steer or Tell on a card.

🤖 Generated with Claude Code

Closes #361

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs