Deploy and cron
These scripts live in the repo root. They are a reference loop for a machine that already has a checkout, not a hosted service, and not the path for a new install (that is Install). Personal files (tweets.db, persona/PERSONA.md, .env, .tokens.json) stay on that machine. deploy.sh recompiles ./tf with the same flags as bun run build.
Run fetch on one host only. The X refresh token rotates on use.
What each script does
| Script | Does |
|---|---|
update.sh | tf refresh: incremental fetch and a flush rebuild. No LLM, no Tavily. |
cron_run.sh | tf cron: incremental fetch, enrich, Notion sync when a key is set, flush, Slack ping if anything is pending. Prefers ./tf, otherwise bun run src/index.ts cron. Logs to logs/cron.log. |
deploy.sh | git pull --ff-only, bun install --frozen-lockfile, recompile ./tf. Does not touch gitignored state. Log: logs/deploy.log. |
backup.sh | Copies tweets.db and persona/PERSONA.md into backups/, keeps 7 daily snapshots, pushes nothing. Log: logs/backup.log. |
tf cron calls enrich, and enrich requires TAVILY_API_KEY. Without that key, cron fails after the fetch. Schedule update.sh (or tf refresh) instead until Tavily is configured. tf update replaces a release binary; it does not refresh tweets.db.
tf cron does not call tf generate. Generation stays something you run, or a separate agent loop, because it spends LLM time and should be read before anything is posted.
Cron
Paths below are the checkout. Use a user crontab on the same account that owns .tokens.json.
# hourly refresh without an LLM
0 * * * * /path/to/tweet-factory/update.sh
# or, when TAVILY_API_KEY is set: fetch + enrich + flush + slack ping
# 0 * * * * /path/to/tweet-factory/cron_run.sh
# nightly local snapshots
15 3 * * * /path/to/tweet-factory/backup.shcron_run.sh and deploy.sh expect bun on PATH or at $HOME/.bun/bin.
A systemd timer can call the same scripts. The repo does not ship a unit file.
Updating the code
./deploy.shSafe to run at the start of a loop. It fast-forwards origin/main only. If you have local commits, the pull fails and the script keeps the current checkout (it logs a warning).
Backups
backups/ is gitignored. Snapshots are named tweets-YYYY-MM-DD.db and PERSONA-YYYY-MM-DD.md. Keep that directory off any public remote. The script keeps the newest 7 of each.
Verify.
./tf refreshexits 0 on the server.logs/cron.logor thetf refreshoutput showsFetch mode: incremental../backup.shthenls backupsshows today’s snapshot whentweets.dbexists.git statusdoes not list.env,.tokens.json, ortweets.db.