A self-hosted inbox for X bookmarks, GitHub stars, and other saved items. Recall Inbox turns scattered saves into a reviewable workflow: sync -> review -> tag/note -> export.
Bookmarks and stars are easy to collect and hard to revisit. Recall Inbox gives them a lightweight processing queue with review states, tags, notes, daily sync, and Markdown export, while keeping the data in infrastructure you control.
- People who save useful posts and repositories but rarely process them later.
- Developers who want GitHub Stars and X bookmarks in one searchable review UI.
- Personal knowledge management users who prefer local Markdown and self-hosted data over another hosted read-it-later service.
Try the hosted demo without creating API tokens:
https://recall-inbox-demo.kapler.workers.dev
- Sync X bookmarks through OAuth 2.0.
- Sync GitHub starred repositories with a personal access token.
- Review saved items with
inbox / keep / action / dismiss, tags, and notes. - Export Markdown files to
outputs/daily/YYYY-MM-DD.md. - Deploy the same review UI and sync job to Cloudflare Workers with D1, or to Vercel with Postgres.
- Local only: use
.data/items.json,yarn sync:x,yarn sync:github, andyarn view. - Cloudflare: deploy the review UI, API, D1 database, and scheduled sync with
yarn cf:release. - Vercel: deploy the same UI and API routes with Postgres and Vercel Cron.
See Roadmap for planned source adapters, review workflow improvements, action exports, GitHub Stars intelligence, and deployment polish.
Configure one or more sources.
- X bookmarks require
X_CLIENT_IDandX_CLIENT_SECRET. - GitHub stars require
GITHUB_TOKEN.
For X bookmarks:
- Create an X Developer Project and App.
- Enable OAuth 2.0 user authentication for the App.
- Use the callback URL that matches your runtime exactly.
- Copy the App
Client IDandClient Secretinto.env, Wrangler secrets, or Vercel environment variables. - Run the one-time X authorization flow. Local mode uses
yarn auth:x; deployed mode usesAdmin->Authorize Xin the review UI.
Recall Inbox requests tweet.read, users.read, bookmark.read, and
offline.access. offline.access lets the app refresh the X token after the
one-time authorization, so scheduled syncs can continue without asking you to
authorize again.
For GitHub stars:
- Create a GitHub personal access token for the account whose stars you want to sync.
- Prefer a fine-grained token with
Starringuser permission set to read. - Store it as
GITHUB_TOKENin.env, Wrangler secrets, or Vercel environment variables.
The GitHub source only reads starred repositories through the authenticated user's starring endpoint. It does not need repository write permissions.
X callback URLs depend on where you run authorization:
- Local CLI:
http://127.0.0.1:17863/callback - Cloudflare Worker:
https://<your-worker-url>/api/auth/x/callback - Vercel:
https://<your-vercel-domain>/api/auth/x/callback
Install dependencies:
yarn installCopy the environment template:
cp .env.example .envSet ADMIN_SECRET, then fill in the source credentials you need. The review UI
uses ADMIN_SECRET to load and edit real saved items. For local X
authorization, use the local callback URL in both the X Developer Portal and
.env:
http://127.0.0.1:17863/callback
Build:
yarn buildAuthorize X only if you use the local X source:
yarn auth:xRun the sync command for each source you configured:
yarn sync:x
yarn sync:githubsync:x is X-only and requires yarn auth:x first. sync:github is
GitHub-only and requires GITHUB_TOKEN. A fine-grained GitHub token with
read-only Starring user permission is enough for personal use.
Review stored items locally:
yarn viewOpen http://127.0.0.1:17864.
Enter ADMIN_SECRET in Sources to unlock stored items and run protected
source actions.
Regenerate Markdown from already stored local data without calling remote APIs:
yarn export:mdLocal data is stored under .data/. Markdown files are written to
outputs/daily/YYYY-MM-DD.md.
Daily Markdown files are grouped by item creation date:
- X bookmarks use the original post
created_atwhen available. - GitHub stars use
starred_at. discoveredAtrecords when the item was first seen by this app.
The local CLI sync can walk available pages until already-known items are found.
The Cloudflare Worker uses SYNC_MAX_PAGES_PER_SOURCE to avoid Worker request
limits. The default is 2.
First large sync: use First sync in the deployed Admin dialog. It performs a
deeper full scan and does not stop just because the newest page is already in
the database. Daily scheduled syncs keep SYNC_MAX_PAGES_PER_SOURCE
conservative and stop once a fully known page is reached.
Run the setup script:
yarn install
yarn cf:setupThe script copies wrangler.example.toml to wrangler.toml when needed,
creates the inbox D1 database, and writes its id back to wrangler.toml.
If you are starting over from an existing wrangler.toml, run:
yarn cf:setup -- --forceIf you are not logged in to Cloudflare yet, run this first:
yarn wrangler loginSet ADMIN_SECRET, plus the source secrets you use:
yarn wrangler secret put ADMIN_SECRET
yarn wrangler secret put X_CLIENT_ID
yarn wrangler secret put X_CLIENT_SECRET
yarn wrangler secret put GITHUB_TOKENADMIN_SECRET protects real saved-item reads and writes, manual sync, and
one-time X authorization. X_CLIENT_ID and X_CLIENT_SECRET are only needed
for X bookmarks. GITHUB_TOKEN is only needed for GitHub stars. Scheduled cron
runs do not need an authorization header.
Build, migrate, and deploy:
yarn cf:releaseManual setup is also possible with Wrangler:
cp wrangler.example.toml wrangler.toml
yarn wrangler d1 create inbox
yarn wrangler d1 migrations apply DB --remote
yarn build
yarn wrangler deployTo deploy a public demo Worker without D1 or source credentials:
yarn cf:deploy-demoThe demo serves built-in sample items from DEMO_MODE and does not persist
visitor changes.
If you use X on Cloudflare, set the X Developer Portal callback URL to:
https://<your-worker-url>/api/auth/x/callback
Then open the deployed review page, click Admin, enter ADMIN_SECRET, and
use Authorize X. The page starts the protected one-time OAuth flow without
putting the secret in the authorization URL. The Worker stores the resulting X
token in D1 and refreshes it during later syncs.
The default cron is 0 21 * * *, which runs at 21:00 UTC and 05:00 in UTC+8.
Adjust wrangler.toml if you want another time.
Run a manual sync:
curl -X POST https://<your-worker-url>/api/sync \
-H "Authorization: Bearer <ADMIN_SECRET>"The deployed review page also has protected admin controls for:
Authorize X: start the one-time X OAuth flow.Sync all: sync all configured sources with the normal page limit.Sync X/Sync GitHub: sync one source.First sync: sync all configured sources with a deeper full-scan page limit.
The same behavior is available through query parameters:
curl -X POST "https://<your-worker-url>/api/sync?source=github&maxPages=50&fullScan=true" \
-H "Authorization: Bearer <ADMIN_SECRET>"source can be all, x, or github. maxPages controls how many pages each
source may fetch for that run. fullScan=true is useful for backfilling older
items when the newest page has already been synced.
Vercel uses the same Vite review UI and /api/* endpoints, backed by Postgres
instead of Cloudflare D1.
Create a Postgres database through Vercel, Neon, Supabase, or another hosted provider, then set these environment variables in Vercel:
POSTGRES_URL=<postgres connection string>
ADMIN_SECRET=<admin password for protected UI actions>
GITHUB_TOKEN=<optional GitHub token>
X_CLIENT_ID=<optional X app client id>
X_CLIENT_SECRET=<optional X app client secret>
SYNC_MAX_PAGES_PER_SOURCE=2
If you use X on Vercel, set the X Developer Portal callback URL to:
https://<your-vercel-domain>/api/auth/x/callback
Apply the SQL files in migrations/ in filename order to initialize or upgrade
the Postgres database. The table and index names are intentionally shared with
D1 so the app logic can run against either store.
The Vercel build command is:
yarn buildThe included vercel.json publishes dist/view and schedules daily sync via:
/api/cron/sync
Manual sync uses the same API shape as Cloudflare:
curl -X POST "https://<your-vercel-domain>/api/sync?source=github&maxPages=50&fullScan=true" \
-H "Authorization: Bearer <ADMIN_SECRET>"- Keep
.env,.data/,outputs/, andwrangler.tomlprivate. - Publish
wrangler.example.toml, not your real Wrangler config. - Use Source Adapter Guide when adding more saved-item sources.
- Rotate
X_CLIENT_SECRET,GITHUB_TOKEN, andADMIN_SECRETif they are ever exposed. - The project is licensed under MIT. Keep
LICENSEin published copies.
Set SUMMARY_API_KEY in .env to enable daily summary and action item
generation. SUMMARY_MODEL and SUMMARY_BASE_URL configure the model and
provider-compatible endpoint. If the key is absent, sync still writes the raw
Markdown list.
