# 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](install.md)). 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`.

```bash
# 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.sh
```

`cron_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

```bash
./deploy.sh
```

Safe 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 refresh` exits 0 on the server. `logs/cron.log` or the `tf refresh` output shows `Fetch mode: incremental`. `./backup.sh` then `ls backups` shows today’s snapshot when `tweets.db` exists. `git status` does not list `.env`, `.tokens.json`, or `tweets.db`.
