I wanted my X bookmarks to feel like a personal archive. The saved posts lived inside one account, the useful parts were hard to search, and the workflow offered no public reading surface.
This project turns that archive into a static site. A Windows machine reads the active Firefox session twice each day. Field Theory downloads the bookmark data into a local JSONL cache. A PowerShell runner creates export files and pushes them into a GitHub repository. Cloudflare Pages builds the frontend from that repository and serves it at signals.asynchronope.my.id.
The site stays static. Its browser code fetches JSON files. The request path contains static files served by Pages.
The project has two repositories: Field Theory CLI, which owns the local sync and export pipeline. my-twitter-bookmarks, a private repository that owns the static frontend and the generated fieldtheory/ snapshot.
The local checkout used while writing this article contains both projects. The frontend checkout sits under .tmp-my-twitter-bookmarks.
The local machine owns the browser session and the source cache. GitHub carries the generated snapshot. Cloudflare Pages serves the public files.
fieldtheory/site is the handoff point. The exporter writes the data there. The static build copies that directory into dist/data.
The production repository builds TypeScript into dist before the CLI runs. The scheduled runner calls the local entry point with Node:
Field Theory reads cookies from the configured Firefox profile, uses the active X session for the bookmark request, and writes records into the data directory.
The JSONL file stores one bookmark record per line. SQLite gives the CLI its local full-text search index. The website uses the generated JSON files, so the database stays on the source machine.
The primary task runs twice per day. The recovery task runs when the user logs in. Its action receives -SkipIfRecentSuccessHours 6, which prevents a login from starting a second sync shortly after a successful scheduled run.
A safe configuration file contains machine paths and repository settings. Browser cookies remain inside the Firefox profile.
StartWhenAvailable lets Windows catch up after a missed start. A powered-off machine pauses the scheduled process. The logon task gives the next session a recovery path.
The production runner lives in sync-bookmarks-to-github.ps1. It has a lock file, retry handling, status output, optional Telegram messages, CSV export, XLSX export, and website export.
The remote update uses a temporary clone. The runner replaces the managed root, creates a commit, and pushes the configured branch:
The GitHub repository receives the generated site data through this path. Git authentication belongs to the Windows machine. A GitHub token can live in the credential manager or in an SSH configuration, with the repository URL chosen to match that setup.
The repository can stay private. Cloudflare Pages supports both private and public GitHub repositories through its Git integration, then publishes the contents of the configured output directory. Visitors receive the generated dist files through the Pages domain. They receive the deployed site, while the Git history, source tree, and local sync scripts remain inside the private repository. See the Cloudflare Pages Git integration guide.
The public boundary sits at dist. Every field copied into dist/data becomes readable by a visitor who knows the file URL. Review the generated JSON before the first deployment and decide which bookmark fields belong in a public archive.
