Fatline

Your own Farcaster node and your own client.

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.

Tu propio nodo de Farcaster y tu propio cliente.

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

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

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.

Who you are on Farcaster

FID. Your Farcaster ID is a number, for example 18350. It is registered in a contract on Optimism (the ID registry). Usernames, posts and follows all hang off this number.
Custody address. The Ethereum address that owns your FID. Its seed phrase is the master key of your account: it can add and remove keys, and move the FID. It never signs everyday posts.
App keys. Everyday posts are signed by app keys (Ed25519 keys, also called signers). Each app you use, such as Warpcast or Firefly, holds its own key, which your custody address authorized. The record of that authorization names the app's own FID. That is how this client can tell you which app made each post.
Messages. A cast, a like, a follow and a profile change are each one signed message: the data, a hash of it, the signature and the key that signed it. Any node can check it without asking anyone.

Quién eres en Farcaster

FID. Tu ID de Farcaster es un número, por ejemplo 18350. Está registrado en un contrato en Optimism (el registro de IDs). Tu nombre de usuario, tus publicaciones y a quién sigues cuelgan de ese número.
Dirección custodia. La dirección de Ethereum dueña de tu FID. Su frase semilla es la llave maestra de tu cuenta: puede agregar y quitar llaves, y mover el FID. Nunca firma las publicaciones de todos los días.
Llaves de app. Las publicaciones de todos los días las firman llaves de app (llaves Ed25519, también llamadas signers). Cada app que usas, como Warpcast o Firefly, tiene su propia llave, autorizada por tu dirección custodia. El registro de esa autorización nombra el FID de la app. Así este cliente puede decirte qué app hizo cada publicación.
Mensajes. Un cast, un like, un follow y un cambio de perfil son cada uno un mensaje firmado: los datos, su hash, la firma y la llave que firmó. Cualquier nodo puede verificarlo sin preguntarle a nadie.

Step 0: a machine for the node

./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.

Why rent at all? A Farcaster node holds every account's current messages: about 600 GB today. Most laptops don't have that much free disk.

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.

Paso 0: una máquina para el nodo

./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.

¿Por qué arrendar? Un nodo de Farcaster guarda los mensajes vigentes de todas las cuentas: unos 600 GB hoy. A la mayoría de los computadores no le sobra tanto disco.

¿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.

Step 1: your read node

./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.

Read nodes and validators. Snapchain, Farcaster's network software, has a small set of validators that agree on the order of messages, in blocks. Your node is a read node: it follows those blocks and keeps its own copy of every message. When you post, your node checks the message and relays it to the validators. You never need a validator's permission to read.
Farcaster or Hypersnap. Hypersnap is a community fork of Snapchain. Both speak the same API and accept the same signed messages. Hypersnap keeps the full history; Farcaster prunes old messages to each account's storage limit. Neither is the default here because it is better: you choose.

The starting snapshot

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.

Healthy means in sync, not just "running"

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.

Why there is no lite node

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.

Paso 1: tu nodo de lectura

./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.

Nodos de lectura y validadores. Snapchain, el software de la red de Farcaster, tiene un grupo pequeño de validadores que acuerdan el orden de los mensajes, en bloques. Tu nodo es de lectura: sigue esos bloques y guarda su propia copia de cada mensaje. Cuando publicas, tu nodo revisa el mensaje y se lo pasa a los validadores. Nunca necesitas permiso de un validador para leer.
Farcaster o Hypersnap. Hypersnap es un fork comunitario de Snapchain. Las dos hablan la misma API y aceptan los mismos mensajes firmados. Hypersnap guarda toda la historia; Farcaster borra mensajes viejos según el límite de almacenamiento de cada cuenta. Ninguna es la opción por defecto por ser mejor: tú eliges.

El snapshot de partida

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.

Sano significa sincronizado, no solo "corriendo"

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.

Por qué no hay un nodo liviano

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.

Step 2: your client

./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".

Paso 2: tu cliente

./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".

No room for a node: copy only the accounts you follow

./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.

This is not a node. Every run says so. It trusts that node: it does not check message signatures or signer keys itself. It does not join the network, and does not help it. It is only as complete and as recent as that node: if the node is behind, so is this.

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 archiveMessagesTime
Farcaster, crackle: 18350 with --following (8 accounts in all)127,333125 s
Farcaster, our node (still catching up): 18350 and @dwr4,824 + 104,545293 s
Hypersnap, haatz: 18350 and @dwr4,824 + 104,54546 s
Hypersnap, our node (still catching up): 18350 and @dwr4,824 + 104,545163 s

Sin espacio para un nodo: copia solo las cuentas que sigues

./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.

Esto no es un nodo. Cada corrida lo dice. Confía en ese nodo: no revisa por sí mismo las firmas de los mensajes ni las llaves. No se une a la red, y no la ayuda. Está tan completo y tan al día como ese nodo: si el nodo va atrasado, esto también.

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íoMensajesTiempo
Farcaster, crackle: 18350 con --following (8 cuentas en total)127.333125 s
Farcaster, nuestro nodo (aún poniéndose al día): 18350 y @dwr4.824 + 104.545293 s
Hypersnap, haatz: 18350 y @dwr4.824 + 104.54546 s
Hypersnap, nuestro nodo (aún poniéndose al día): 18350 y @dwr4.824 + 104.545163 s

Posting: your client's own app key

./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
Storage rent and server bills are different things. Storage rent is paid onchain, per account, and sets how many messages the network keeps for you. It does not pay for any server. Your node's server is a separate bill, paid to whoever hosts it.

Status: the key registration and every action were tested against a fake node, and crackle accepted the message formats. untested with a real account.

Publicar: la llave propia de tu cliente

./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
El arriendo de almacenamiento y la cuenta del servidor son cosas distintas. El arriendo de almacenamiento se paga onchain, por cuenta, y define cuántos mensajes guarda la red para ti. No paga ningún servidor. El servidor de tu nodo es otra cuenta, que se le paga a quien lo hospeda.

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.

Choosing which apps you read

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.

Elegir qué apps lees

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.

What it costs, and how to stop paying

ItemPrice (Hetzner, checked 2026-10-22)
Server cax31 (8 ARM CPUs, 16 GB RAM) with a 700 GB volumeabout $2.75 per day
A second node (the other network), on its own server and volumeabout the same again
Your clientfree 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.

Cuánto cuesta, y cómo dejar de pagar

QuéPrecio (Hetzner, revisado 2026-10-22)
Servidor cax31 (8 CPU ARM, 16 GB de RAM) con un volumen de 700 GBunos USD 2,75 al día
Un segundo nodo (la otra red), en su propio servidor y volumenmás o menos lo mismo otra vez
Tu clientegratis 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.

When something goes wrong

"Sold out" when renting

The message lists the server types in stock in that location. Pick one with --type, or another location with --location.

The snapshot stopped

Run step 1 again. Finished shards are kept, and slow pieces are retried.

The client says the node you chose is not answering

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.

Everything else

./fatline doctor checks your machine and every configured node. Problems and questions: GitHub issues.

Cuando algo falla

"Sold out" al arrendar

El mensaje lista los tipos de servidor con stock en esa ubicación. Elige uno con --type, u otra ubicación con --location.

El snapshot se detuvo

Corre de nuevo el paso 1. Los shards terminados se conservan y las piezas lentas se reintentan.

El cliente dice que el nodo que elegiste no responde

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.

Todo lo demás

./fatline doctor revisa tu máquina y cada nodo configurado. Problemas y preguntas: issues en GitHub.

Give your client a life

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.

Dale vida a tu cliente

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.

What we have tested, and what we haven't

PartStatus
Reading Farcaster and Hypersnap through public nodesworks
Choosing a node; a clear error when it is downworks against real nodes
Showing or hiding casts by appworks on real data
Renting the node's server on Hetznerdone once, our own node, 2026-10-22
All three commands, fresh, start to finishuntested
Our own nodes answering, shown as "behind" until in syncworks, both networks, 2026-10-22
A read node fully in syncworks 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 accountuntested
A replicating (lighter) nodenot possible today: both networks' replicators refuse key messages
A stranger following this page from scratchnot yet; could it be you?

Qué probamos y qué no

ParteEstado
Leer Farcaster y Hypersnap desde nodos públicosfunciona
Elegir un nodo; un error claro si se caefunciona contra nodos reales
Mostrar u ocultar casts según la appfunciona con datos reales
Arrendar el servidor del nodo en Hetznerhecho una vez, nuestro nodo, 2026-10-22
Los tres comandos, desde cero, de principio a finsin probar
Nuestros nodos respondiendo, marcados "atrasado" hasta sincronizarfunciona, ambas redes, 2026-10-22
Un nodo de lectura completamente sincronizadofunciona 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 realsin 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 cerotodavía no; ¿podrías ser tú?