Skip to content
This repository was archived by the owner on Oct 28, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Allthing is a Farcaster client for reading, written in Rust: a Leptos WebAssembly app plus a workers-rs API Worker, deployed to Cloudflare Workers (Free plan) at https://allthing.social. Read `docs/ARCHITECTURE.md` first.

- **One QR flow: sign in, and write, with a key the reader approves once.** By the owner's decision, where the Worker endorses keys there is one approval and one dialog: the reader approves Allthing's key request in the Farcaster app (a QR code on a computer, a link to the app on a phone), which signs them in (`POST /api/v1/auth/key`) and lets them cast, reply, quote, like, recast, follow and delete from here, with no second scan or separate grant step. A reader signed in without a key in this browser (signed in before keys, after Revoke permissions, or with its storage cleared) meets the same dialog, in its approve form, on their first write (`Session::grant`), never by itself on a page load. Never add a second approval dialog or QR flow. Sign In With Farcaster by QR code is only the fallback where the Worker endorses no keys, and makes no relay request where it does (`allthing-worker/src/auth.rs`, `allthing-core/src/siwf.rs`, `allthing-web/src/components/signin.rs`; see `docs/ARCHITECTURE.md#sign-in`). Once a reader has approved Allthing in the Farcaster app, casts, replies, quotes, likes, recasts, follows and deletes go from Allthing: the browser makes and keeps the key and signs (`allthing-core/src/app_key.rs` and `message.rs`, `allthing-web/src/keys.rs` and `components/writer.rs`; see `docs/ARCHITECTURE.md#liking-and-recasting`), and the Worker keeps scheduled casts the browser signed until their time (`allthing-worker/src/scheduled_casts.rs`, `allthing-data/src/scheduled.rs`). Allthing asks for those keys as its own Farcaster account, @allthingapp (FID 3356318, `ALLTHING_FID` in `wrangler.toml`), which its owner registered for it, and shows the casts "via Allthing" (`allthing-core/src/clients.rs`). By the owner's decision that is Allthing's only account: never add another, a seed phrase import or a wallet connection. The Worker endorses readers' keys with that account's custody key, the `ALLTHING_CUSTODY_KEY` secret, set in Cloudflare only (`allthing-worker/src/app_key.rs`; see `docs/DEPLOY.md#secrets`), and uses it for nothing else; it never holds a reader's key or signs as a reader. Until the secret is set (`writes.ready` in `/api/v1/status`), and for a reader signed out, a write opens the cast, the profile or a draft ready to post in the Farcaster app instead (`allthing-web/src/components/handoff.rs`, `allthing-core/src/compose.rs`; see `docs/ARCHITECTURE.md#handing-writes-to-the-farcaster-app`). Never add other login methods, wallet connections or write paths unless asked to. Messages (`/messages`) is Allthing's own, on SpacetimeDB (`allthing-web/src/pages/messages`, `spacetime/`; see `docs/ARCHITECTURE.md#messages-on-spacetimedb`): never add Farcaster Direct Cast API calls or an API-key paste step to it unless asked.
- **No automatic account-based exclusions.** Allthing shows no account labels; spam is judged by a cast's content (see Mini apps and spam below). The owner's explicit exception is reader-selected private Mute and Block: hide content involving those accounts throughout that reader's Allthing view, including identifiable mentions, quoted/replied-to/recasting accounts and notifications. Keep these preferences caller-private and synced through SpacetimeDB; Block also rejects new Allthing DMs in either direction using verified FIDs. This does not delete public posts or establish a block in another Farcaster client. Preserve the recognition limits and undo/sync explanations in `docs/ARCHITECTURE.md#private-mute-and-block`; never turn these choices into a shared author blacklist.
- **No automatic account-based exclusions.** Allthing shows no account labels; spam is judged by a cast's content (see Mini apps and spam below). The owner's explicit exception is reader-selected private Mute and Block: hide content involving those accounts throughout that reader's Allthing view, including identifiable mentions, quoted/replied-to/recasting accounts and notifications. Keep these preferences caller-private and synced through SpacetimeDB; Block also rejects new Allthing DMs in either direction using verified FIDs. This does not delete public posts or establish a block in another Farcaster client. The owner also explicitly chose stronger reader-selected Show less: omit a stable approximately 90% of that author's Home, Following and channel candidates and downrank the remainder; keep New chronological and direct profiles/search available. It remains a private browser preference, not an automatic shared account blacklist. Preserve the recognition limits and undo/sync explanations in `docs/ARCHITECTURE.md#private-mute-and-block`; never turn these choices into a shared author blacklist.
- **Rust first.** The owner prefers Rust for application behavior and native tooling. Put pure shared rules in `allthing-core`, interactive UI in `allthing-web`, and native build/check policy in `xtask`. Keep `web/paint.js`'s inert first-card renderer: the owner chose it after a paired cold-load comparison beat the Rust prototype (see `docs/PERFORMANCE.md#measured-exception-the-javascript-first-card-renderer`). Retain the existing Node static test server (`e2e/pages-server.mjs`) after an unresolved pre-mount stall in migration CI; the server's role in that stall was not established (see `docs/PERFORMANCE.md#retained-node-static-test-server`). Keep the small JavaScript loader and inline preload/data hints, the SpacetimeDB TypeScript SDK adapter/generated bindings, and official Playwright browser tests at their platform boundaries. CSS, SQL, HTML and config remain platform data. Preserve measured performance, license rules and independent test oracles; do not mask handwritten files with Linguist attributes.
- **Where code goes.**
- Pure logic and data types, with unit tests, go in `crates/allthing-core`.
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch

### Added

- A persistent DAU navigation link on desktop and phones, with a coverage panel showing the Hypersnap source, snapshot update time, verified start and each shard's block progress. Incomplete totals are marked as lower bounds; responses without coherent verification evidence show a waiting explanation instead of figures.
- Private, account-wide Mute and Block controls on profiles and hover cards, with searchable undo controls in Settings and keyboard/touch-accessible help. Preferences sync through SpacetimeDB and suppress posts, quoted/replied-to/recasting accounts, identifiable mentions and account links, notifications and their unread counts. Block also hides existing Allthing conversations locally and rejects new DMs in either direction using verified account ownership; public posts and other Farcaster clients are unaffected.
- Durable offline mute/block intent, independent per-choice revisions and retained clear tombstones. Fresh signed-in sessions wait for private filters before drawing content; realtime changes remove already shown content, and newer remote choices supersede stale offline intent.
- A private Library for bookmarks and seen history synced across signed-in devices through SpacetimeDB, plus paginated Farcaster likes and recasts. Seen history no longer expires after 30 days or 2,000 posts; fresh Home candidates wait for synced history, while already drawn cards keep their place. Library includes loaded-post filtering, activity times, retry, Back restoration, Mark unread and Clear history controls.
Expand All @@ -16,10 +17,13 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch

### Changed

- Show less now omits roughly 90% of that account's feed posts across Home, Following and channels, with stable selection and a stronger penalty for remaining Hot/Top posts. New keeps chronological order; direct profiles remain complete and the same button undoes the choice.

- Following opens with New selected; For you still opens with Hot. Explicit sort choices remain selected when changing the time range.

### Fixed

- Count active accounts from checked, consecutive Hypersnap events with canonical block times carried across pages, declared event totals and both shards' coverage. The new verification epoch keeps old rows without certifying their totals. Full account and 32-byte signing-key identities prevent prefix collisions; incomplete attribution stays unknown, and a fenced atomic save rejects stale concurrent runs. Action totals are labelled as merge events because the same message can appear on both shards.
- Recover one confirmed missing entry-loader request without reloading or changing drafts and sessions; persistent failures show an accessible Reload button even if early Home data arrives later. Healthy startup adds no recovery traffic.

- Serve HTML from the same deployment as its asset manifest with no-store caching; missing scripts and WebAssembly return real 404s instead of immutable HTML. A missing startup asset can recover once when a bounded check confirms a different same-origin build; other startup errors retain the manual Reload panel.
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Allthing is an independent Farcaster client, written in Rust, that shows trendin

<p align="center">
<img src="docs/screenshots/profile.webp" alt="A profile: bio, website, followers and following, join date, NS vote and wallet activity by chain" width="49%">
<img src="docs/screenshots/dau.webp" alt="The daily active accounts page, counted as SnapMeter counts them" width="49%">
<img src="docs/screenshots/dau.webp" alt="The daily active accounts page" width="49%">
</p>

## Features
Expand All @@ -37,11 +37,11 @@ Allthing is an independent Farcaster client, written in Rust, that shows trendin
- **Posts and threads.** A post with its parent, quoted casts (inline up to three levels) and threaded replies that collapse and expand.
- **Honest engagement.** Likes, recasts and replies, the only counts Farcaster has. Hovering or tapping a count lists who liked, recasted or replied.
- **Hover cards.** A name or picture opens a profile card (bio, followers and following, join date, NS vote, wallet activity by chain), and names inside those lists open nested cards of their own.
- **Profiles.** Bio, website, followers and following pages (`/u/<name>/followers`, `/following`), the [NS vote](docs/VOTE.md) and wallet activity by chain for verified addresses. Favorite and Show less, kept in your browser, raise or lower an account's casts in your feeds without hiding anything.
- **Profiles.** Bio, website, followers and following pages (`/u/<name>/followers`, `/following`), the [NS vote](docs/VOTE.md) and wallet activity by chain for verified addresses. Favorite and Show less are private preferences kept in your browser. Favorite raises an account's casts in Hot and Top; Show less omits about 90% of their posts from Home, Following and channel feeds and ranks the rest much lower in Hot and Top. New stays chronological, direct profiles remain available, and pressing Show less again undoes it.
- **Media in place.** Images open in an accessible viewer; Farcaster's HLS videos play inline (through a small HLS player written in Rust where the browser has none), muted until you turn sound on. Media loads straight from its hosts.
- **Pepe emoji and reactions.** `:pepe_name:` shows one of 219 Pepe emoji, mostly animated. Pepe reactions (one-emoji replies) gather under casts as chips.
- **Provenance.** Each cast names the app that registered its signing key ([docs/PROVENANCE.md](docs/PROVENANCE.md)).
- **Daily active accounts.** [/dau](https://allthing.social/dau) counts Farcaster's active accounts from the network's event stream, exactly as [SnapMeter](https://github.com/ael-dev3/SnapMeter) does.
- **Daily active accounts.** [/dau](https://allthing.social/dau) counts unique Farcaster accounts from checked Hypersnap events, using [SnapMeter](https://github.com/ael-dev3/SnapMeter)'s activity-type definitions. It shows each shard's checkpoints and gaps; partial totals are lower bounds and complete windows count each account once. It checks this provider's events, not the whole network independently.
- **Allthing's poll.** One question on the front page: would you like an Allthing mobile client?
- **Less noise, judged by content.** Spam caught by a few fixed content rules is left out by the Worker. Casts that embed or link to mini apps or frames, which Allthing doesn't run, are hidden too unless you turn on Show mini app casts in Settings; then each links to open in Farcaster. There are no automatic account-based exclusions; signed-in readers can choose their own private Mute and Block preferences.

Expand All @@ -59,7 +59,7 @@ Allthing is an independent Farcaster client, written in Rust, that shows trendin
### Fast and frugal

- **One API call per page**, cached at the edge, so the whole site runs on the Cloudflare Workers Free plan.
- **Early paint.** For anonymous readers, a small JavaScript renderer draws the front page's first cards from its existing response while the Rust app downloads. Signed-in Home waits for private history membership and account filters to avoid flashing previously read or muted/blocked posts. It stays in JavaScript because it beat the Rust prototype in the [paired cold-load comparison](docs/PERFORMANCE.md#measured-exception-the-javascript-first-card-renderer).
- **Early paint.** For anonymous readers without Show less choices, a small JavaScript renderer draws the front page's first cards from its existing response while the Rust app downloads. Feeds with Show less choices wait for the Rust filter, so omitted posts do not flash first. Signed-in Home waits for private history membership and account filters to avoid flashing previously read or muted/blocked posts. The early renderer stays in JavaScript because it beat the Rust prototype in the [paired cold-load comparison](docs/PERFORMANCE.md#measured-exception-the-javascript-first-card-renderer).
- **Split WebAssembly.** Pages, the composer, writing, sign-in and the DAU dashboard are code of their own, fetched when used, so every visit downloads less.
- **Instant navigation.** Posts open from the feed's own data, cards are prefetched within a capped budget, and Back returns to the same place. CI holds smoothness to budgets ([docs/PERFORMANCE.md](docs/PERFORMANCE.md)).
- **Accessible.** Keyboard throughout, alt text, focus kept in dialogs, reduced motion respected, and it fits a phone.
Expand Down
Loading
Loading