No API keys from anyone. Farcaster or Hypersnap: your choice, as equals. This page explains each step as you go.
Fatline is an open protocol for being on Farcaster on your own terms. You choose the network. You choose the node, and the client always says which one it reads from. And the client can pay for its own server from a USDC vault. This repository is its first implementation. Formerly Infinicaster.
Sin llaves de API de nadie. Farcaster o Hypersnap: tú eliges, en igualdad. Esta página explica cada paso mientras avanzas.
Fatline es un protocolo abierto para estar en Farcaster en tus propios términos. Tú eliges la red. Tú eliges el nodo, y el cliente siempre dice desde cuál lee. Y el cliente puede pagar su propio servidor desde una bóveda de USDC. Este repositorio es su primera implementación. Antes se llamaba Infinicaster.
Before you start
~/.hetzner-token (chmod 600).git clone https://github.com/jpfraneto/fatline && cd fatline
./fatline compute # (0) rent a machine that can hold a node: price first, then you type "create"
./fatline node farcaster # (1) your read node on it, no API keys (or: node hypersnap)
./fatline client # (2) your client, reading from your node, on http://localhost:8787
untested end to end Each step has been run on its own. A complete fresh run of all three, start to finish, has not been done yet. Our own node was built with an earlier one-step version of steps 0 and 1.
No room for a node? ./fatline follow copies only the accounts you choose from one node you pick. It is not a node.
Antes de empezar
~/.hetzner-token (chmod 600).git clone https://github.com/jpfraneto/fatline && cd fatline
./fatline compute # (0) arrienda una máquina capaz de tener un nodo: primero el precio, luego escribes "create"
./fatline node farcaster # (1) tu nodo de lectura ahí, sin llaves de API (o: node hypersnap)
./fatline client # (2) tu cliente, leyendo de tu nodo, en http://localhost:8787
sin probar de punta a punta Cada paso se ha corrido por separado. Una corrida nueva y completa de los tres, de principio a fin, todavía no se ha hecho. Nuestro propio nodo se armó con una versión anterior que juntaba los pasos 0 y 1.
¿No te cabe un nodo? ./fatline follow copia solo las cuentas que elijas desde un nodo que tú eliges. No es un nodo.
./fatline compute --quote # price only, nothing is created
./fatline compute # asks you to type "create"
It picks the cheapest server type in stock with at least 16 GB of RAM (on 2026-10-22: cax31, 8 ARM CPUs), adds a 700 GB volume, prints the price and asks before creating anything. It rents the machine only; step 1 puts the node on it. Everything it creates is written to .fatline/hetzner.json, so it can be deleted exactly.
Already have a machine with Docker, 16 GB of RAM and about 700 GB free? Skip this step and use ./fatline node farcaster --local there. ./fatline doctor measures your machine and tells you which path fits.
Prefer paying in USDC? ./fatline compute --provider agentmetal rents by the day over x402. untested with real money.
./fatline compute --quote # solo el precio, no crea nada
./fatline compute # te pide escribir "create"
Elige el tipo de servidor más barato con stock y al menos 16 GB de RAM (el 2026-10-22: cax31, 8 CPU ARM), le agrega un volumen de 700 GB, muestra el precio y pregunta antes de crear algo. Solo arrienda la máquina; el paso 1 le pone el nodo. Todo lo que crea queda anotado en .fatline/hetzner.json, para poder borrarlo exacto.
¿Ya tienes una máquina con Docker, 16 GB de RAM y unos 700 GB libres? Sáltate este paso y usa ./fatline node farcaster --local ahí. ./fatline doctor mide tu máquina y te dice qué camino te sirve.
¿Prefieres pagar en USDC? ./fatline compute --provider agentmetal arrienda por día vía x402. sin probar con dinero real.
./fatline node farcaster # or: ./fatline node hypersnap
It installs that network's node on the machine from step 0 and follows the starting snapshot as it streams in (about 400 GB, roughly 1 to 3 hours). When the node answers on /v1/info, it becomes your own node in fatline.config.json, so step 2 reads from it. A server holds one network; it refuses to put the second one next to the first.
With --local, it installs on the machine you are on instead: it downloads that network's official bootstrap script, shows you its address and checksum, and asks before running it.
A new node starts from a snapshot of the network instead of replaying years of blocks. On a rented server, this setup streams it straight to disk, three shards at once: about 400 GB compressed, in 5,695 pieces, about 600 GB unpacked. Snapchain's own loader keeps up to three copies on disk at its peak; streaming keeps one. The node keeps one day of blocks by default (pruning.block_retention), not the whole history.
Our two nodes, measured on 2026-10-22: after the snapshot, each one answered while still 70,000 to 100,000 blocks behind, and caught up at about 270 blocks a minute. Farcaster: answered at 06:42 UTC, fully in sync at 12:25 UTC: 5 h 43 min. A reboot then took 47 s to answer and 62 s to be back in sync. Hypersnap: answered at 10:21 UTC, then stood still for five and a half hours: the validator list in Hypersnap's repository is missing Farcaster's validator change of 2026-10-22 (issue #41). Our setup now takes the list from Snapchain, and the node moves again. Its time to full sync: not measured yet.
A node is healthy when /v1/info shows a small blockDelay on every shard. An open port is not enough. The client and its status page both use this rule.
A lighter node would copy the current state from another node instead of starting from a snapshot. Today the replicators of both Snapchain and Hypersnap refuse the messages that add and remove app keys, so a replica can't follow which keys belong to which account. A full replica would still be about 300–400 GB. If that is too much, see copying only the accounts you follow.
./fatline node farcaster # o: ./fatline node hypersnap
Instala el nodo de esa red en la máquina del paso 0 y sigue el snapshot de partida mientras llega (unos 400 GB, más o menos 1 a 3 horas). Cuando el nodo responde en /v1/info, queda como tu propio nodo en fatline.config.json, y el paso 2 lee de él. Un servidor tiene una sola red; no pone la segunda al lado de la primera.
Con --local, lo instala en la máquina donde estás: descarga el script oficial de esa red, te muestra su dirección y su checksum, y pregunta antes de correrlo.
Un nodo nuevo parte de un snapshot de la red en vez de repetir años de bloques. En un servidor arrendado, esta instalación lo transmite directo al disco, tres shards a la vez: unos 400 GB comprimidos, en 5.695 piezas, unos 600 GB descomprimidos. El cargador de Snapchain guarda hasta tres copias en su peor momento; transmitiendo queda una. El nodo guarda un día de bloques por defecto (pruning.block_retention), no toda la historia.
Nuestros dos nodos, medidos el 2026-10-22: después del snapshot, cada uno respondió estando aún 70.000 a 100.000 bloques atrás, y se fue poniendo al día a unos 270 bloques por minuto. Farcaster: respondió a las 06:42 UTC y quedó sincronizado a las 12:25 UTC: 5 h 43 min. Después, un reinicio tardó 47 s en responder y 62 s en volver a estar sincronizado. Hypersnap: respondió a las 10:21 UTC y luego se quedó quieto cinco horas y media: a la lista de validadores del repositorio de Hypersnap le falta el cambio de validadores de Farcaster del 2026-10-22 (issue #41). Nuestra instalación ahora toma la lista de Snapchain, y el nodo avanza de nuevo. Su tiempo hasta sincronizar: aún sin medir.
Un nodo está sano cuando /v1/info muestra un blockDelay pequeño en cada shard. Un puerto abierto no basta. El cliente y su página de estado usan esta regla.
Un nodo más liviano copiaría el estado actual desde otro nodo en vez de partir de un snapshot. Hoy los replicadores de Snapchain y de Hypersnap rechazan los mensajes que agregan y quitan llaves de app, así que una réplica no puede seguir qué llaves son de qué cuenta. Una réplica completa igual pesaría unos 300–400 GB. Si es demasiado, mira copiar solo las cuentas que sigues.
./fatline client
Step 1 already told it where your node is. (A node somewhere else? ./fatline init --node http://<IP>:3381.) It installs, builds and starts the client on http://localhost:8787. Your phone can open it too, if it can reach your computer.
The client always says which node it is reading from, at the top of the page. In Settings you choose the network (Farcaster or Hypersnap) and the node:
Besides your own, the list includes public nodes run by others, such as crackle.farcaster.xyz (Farcaster) and haatz.quilibrium.com (Hypersnap), and the two nodes we run for this project. They are always labeled "public".
./fatline client
El paso 1 ya le dijo dónde está tu nodo. (¿Un nodo en otra parte? ./fatline init --node http://<IP>:3381.) Instala, compila y parte el cliente en http://localhost:8787. Tu teléfono también puede abrirlo si alcanza a tu computador.
El cliente siempre dice desde qué nodo está leyendo, arriba de la página. En Ajustes eliges la red (Farcaster o Hypersnap) y el nodo:
Además del tuyo, la lista trae nodos públicos de otros, como crackle.farcaster.xyz (Farcaster) y haatz.quilibrium.com (Hypersnap), y los dos nodos que corremos para este proyecto. Siempre aparecen como "público".
./fatline follow 18350 @dwr --network farcaster --node crackle --once
./fatline follow 18350 --following --network hypersnap --node haatz # keeps following; Ctrl+C stops it, a re-run continues
./fatline follow list
It copies the accounts you name (with --following, also everyone they follow) from one node you pick, Farcaster or Hypersnap, your own or a public one, into the client's archive. Open #/archive/<fid> in the client to read one. --node takes a word of the node's name or host, or its URL; only that node is read, and it never switches.
If the node is down, you get a clear error and nothing changes. If it is behind, it is used, with a warning that says how far behind.
| Measured 2026-10-22, into an empty archive | Messages | Time |
|---|---|---|
Farcaster, crackle: 18350 with --following (8 accounts in all) | 127,333 | 125 s |
| Farcaster, our node (still catching up): 18350 and @dwr | 4,824 + 104,545 | 293 s |
| Hypersnap, haatz: 18350 and @dwr | 4,824 + 104,545 | 46 s |
| Hypersnap, our node (still catching up): 18350 and @dwr | 4,824 + 104,545 | 163 s |
./fatline follow 18350 @dwr --network farcaster --node crackle --once
./fatline follow 18350 --following --network hypersnap --node haatz # sigue copiando; Ctrl+C lo detiene, y al correrlo de nuevo continúa
./fatline follow list
Copia las cuentas que nombras (con --following, también a todos los que ellas siguen) desde un nodo que tú eliges, de Farcaster o de Hypersnap, tuyo o público, al archivo del cliente. Abre #/archive/<fid> en el cliente para leer una. --node acepta una palabra del nombre o del host del nodo, o su URL; se lee solo ese nodo, y nunca cambia a otro.
Si el nodo está caído, ves un error claro y no cambia nada. Si va atrasado, se usa igual, con un aviso que dice cuánto.
| Medido el 2026-10-22, en un archivo vacío | Mensajes | Tiempo |
|---|---|---|
Farcaster, crackle: 18350 con --following (8 cuentas en total) | 127.333 | 125 s |
| Farcaster, nuestro nodo (aún poniéndose al día): 18350 y @dwr | 4.824 + 104.545 | 293 s |
| Hypersnap, haatz: 18350 y @dwr | 4.824 + 104.545 | 46 s |
| Hypersnap, nuestro nodo (aún poniéndose al día): 18350 y @dwr | 4.824 + 104.545 | 163 s |
./fatline identity --fid <your FID> --dry-run # checks everything, registers nothing
./fatline identity --fid <your FID> # registers this client's key
Run it in your own terminal. It asks for your seed phrase in a hidden prompt, derives your custody address the standard way, and stops if that address does not own the FID you gave. It creates a new app key for this client and registers it with a message your custody address signs. No transaction, no gas. The key can post, react, follow and edit your profile, nothing else. The seed phrase is forgotten as soon as the key is registered, and never saved.
Then you can cast, reply, like, recast, follow and delete. Each action shows sending, then confirmed only once your node returns it when asked.
./fatline identity show # is the key active?
./fatline identity revoke # remove it from the network and from this machine
Status: the key registration and every action were tested against a fake node, and crackle accepted the message formats. untested with a real account.
./fatline identity --fid <tu FID> --dry-run # revisa todo, no registra nada
./fatline identity --fid <tu FID> # registra la llave de este cliente
Córrelo en tu propia terminal. Te pide tu frase semilla en un campo oculto, deriva tu dirección custodia de la forma estándar, y se detiene si esa dirección no es dueña del FID que diste. Crea una llave nueva para este cliente y la registra con un mensaje que firma tu dirección custodia. Sin transacción, sin gas. La llave puede publicar, reaccionar, seguir y editar tu perfil, nada más. La frase semilla se olvida apenas se registra la llave, y nunca se guarda.
Después puedes hacer casts, responder, dar like, recastear, seguir y borrar. Cada acción muestra enviando, y confirmado solo cuando tu nodo la devuelve al preguntarle.
./fatline identity show # ¿está activa la llave?
./fatline identity revoke # la quita de la red y de esta máquina
Estado: el registro de la llave y cada acción se probaron contra un nodo falso, y crackle aceptó el formato de los mensajes. sin probar con una cuenta real.
In My people, every cast says which app made it ("via @warpcast"), read from the record of the key that signed it. Tap an app to hide its casts, or show only that app. Casts whose key doesn't name an app follow a rule you can see and change.
Measured through crackle on 2026-10-22, with @dwr, @v and @vitalik: 20 of 20 casts were traced to an app (@warpcast and @fireflyapp). Hiding one left only the other's casts.
En Mi gente, cada cast dice qué app lo hizo ("vía @warpcast"), leído del registro de la llave que lo firmó. Toca una app para ocultar sus casts, o para ver solo esa. Los casts cuya llave no nombra una app siguen una regla que puedes ver y cambiar.
Medido a través de crackle el 2026-10-22, con @dwr, @v y @vitalik: 20 de 20 casts tenían app conocida (@warpcast y @fireflyapp). Al ocultar una quedaron solo los casts de la otra.
| Item | Price (Hetzner, checked 2026-10-22) |
|---|---|
Server cax31 (8 ARM CPUs, 16 GB RAM) with a 700 GB volume | about $2.75 per day |
| A second node (the other network), on its own server and volume | about the same again |
| Your client | free on your own computer |
Billed by the hour. --quote shows the exact price before anything is created.
./fatline compute hetzner down # deletes the server and its volume; billing stops
It deletes only what step 0 created, using the record in .fatline/hetzner.json.
| Qué | Precio (Hetzner, revisado 2026-10-22) |
|---|---|
Servidor cax31 (8 CPU ARM, 16 GB de RAM) con un volumen de 700 GB | unos USD 2,75 al día |
| Un segundo nodo (la otra red), en su propio servidor y volumen | más o menos lo mismo otra vez |
| Tu cliente | gratis en tu propio computador |
Se cobra por hora. --quote muestra el precio exacto antes de crear algo.
./fatline compute hetzner down # borra el servidor y su volumen; se deja de cobrar
Borra solo lo que creó el paso 0, usando el registro en .fatline/hetzner.json.
The message lists the server types in stock in that location. Pick one with --type, or another location with --location.
Run step 1 again. Finished shards are kept, and slow pieces are retried.
That is on purpose: it never switches nodes without telling you. Check the node with ./fatline status or compute hetzner status, or choose another node in Settings.
./fatline doctor checks your machine and every configured node. Problems and questions: GitHub issues.
El mensaje lista los tipos de servidor con stock en esa ubicación. Elige uno con --type, u otra ubicación con --location.
Corre de nuevo el paso 1. Los shards terminados se conservan y las piezas lentas se reintentan.
Es a propósito: nunca cambia de nodo sin avisarte. Revisa el nodo con ./fatline status o compute hetzner status, o elige otro en Ajustes.
./fatline doctor revisa tu máquina y cada nodo configurado. Problemas y preguntas: issues en GitHub.
Why "Fatline": a fatline, as we use the word, is a line you hold at both ends. Your keys sign at one end, your own node listens at the other, and nobody in between rents you the line and can take it back. Keeping a line open costs something, so this one carries its own purse. The word comes from Dan Simmons' novel Hyperion; what it means here is ours.
The last chapter is that purse: a client can pay for its own server. In the client, Launch an app creates a USDC vault on Base, and optionally a coin on Clanker whose trading fees go to that vault, in USDC. The server pays itself from the vault. If the vault runs dry, the server stops being paid and the app dies. Anyone can feed it.
Status: proven on a local copy of Base with fake money, against the real Clanker and Uniswap contracts. untested with real money; the contracts are not deployed on Base yet, and have had no external audit.
Por qué "Fatline": una fatline, como usamos la palabra, es una línea que sostienes por ambos extremos. Tus llaves firman en un extremo, tu propio nodo escucha en el otro, y nadie en medio te arrienda la línea ni puede quitártela. Mantener una línea abierta cuesta algo, así que esta lleva su propia bolsa. La palabra viene de la novela Hyperion, de Dan Simmons; lo que significa aquí es nuestro.
El último capítulo es esa bolsa: un cliente puede pagar su propio servidor. En el cliente, Lanzar una app crea una bóveda de USDC en Base y, si quieres, una moneda en Clanker cuyas comisiones van a esa bóveda, en USDC. El servidor se paga desde la bóveda. Si la bóveda se vacía, el servidor deja de pagarse y la app muere. Cualquiera puede alimentarla.
Estado: probado en una copia local de Base con dinero falso, contra los contratos reales de Clanker y Uniswap. sin probar con dinero real; los contratos aún no están desplegados en Base y no han tenido auditoría externa.
| Part | Status |
|---|---|
| Reading Farcaster and Hypersnap through public nodes | works |
| Choosing a node; a clear error when it is down | works against real nodes |
| Showing or hiding casts by app | works on real data |
| Renting the node's server on Hetzner | done once, our own node, 2026-10-22 |
| All three commands, fresh, start to finish | untested |
| Our own nodes answering, shown as "behind" until in sync | works, both networks, 2026-10-22 |
| A read node fully in sync | works Farcaster: 5 h 43 min after it answered, back in sync 62 s after a reboot. Hypersnap: catching up |
Copying only chosen accounts (follow, not a node) | works on real nodes, both networks |
| Registering an app key and posting with a real account | untested |
| A replicating (lighter) node | not possible today: both networks' replicators refuse key messages |
| A stranger following this page from scratch | not yet; could it be you? |
| Parte | Estado |
|---|---|
| Leer Farcaster y Hypersnap desde nodos públicos | funciona |
| Elegir un nodo; un error claro si se cae | funciona contra nodos reales |
| Mostrar u ocultar casts según la app | funciona con datos reales |
| Arrendar el servidor del nodo en Hetzner | hecho una vez, nuestro nodo, 2026-10-22 |
| Los tres comandos, desde cero, de principio a fin | sin probar |
| Nuestros nodos respondiendo, marcados "atrasado" hasta sincronizar | funciona, ambas redes, 2026-10-22 |
| Un nodo de lectura completamente sincronizado | funciona Farcaster: 5 h 43 min después de responder, sincronizado de nuevo 62 s después de un reinicio. Hypersnap: poniéndose al día |
Copiar solo algunas cuentas (follow, no es un nodo) | funciona con nodos reales, ambas redes |
| Registrar una llave y publicar con una cuenta real | sin probar |
| Un nodo replicador (más liviano) | no es posible hoy: los replicadores de ambas redes rechazan los mensajes de llaves |
| Una persona nueva siguiendo esta página desde cero | todavía no; ¿podrías ser tú? |