Check again next month
Put saylent verify on a cron entry or a scheduled GitHub Actions job, keep the movement reports, and know when to deploy the app instead.
You do not need the full app to keep measuring. saylent verify is one
command against one baseline file, so a cron entry or a scheduled GitHub
Actions job is enough to re-check a brand on a schedule and keep the results.
Two things make it work unattended:
--yes. Without a terminal to answer "Run it? [Y/n]", the CLI refuses and printsNot a terminal. Re-run with --yes.rather than reading the empty line as a yes and spending money nobody agreed to.--max-usd <n>. The daily cap is a local ledger at~/.saylent/spend.json. A CI runner is a fresh machine every time, so that ledger is always empty there and the daily cap protects nothing.--max-usdis the one that travels: the run refuses before it starts if the high estimate is above your number.
On a machine you keep (cron)
Run saylent keys once as the user the job runs as. Keys land in
~/.saylent/config.json, chmod 600, and every later run reads them from
there, so no secret goes on the crontab line:
# 09:00 UTC on the 1st of each month
0 9 1 * * cd /home/me/saylent && npx saylent verify ./example.com/2026-09-14/run.json --yes --max-usd 2 >> verify.log 2>&1On a schedule you do not host (GitHub Actions)
Commit the baseline run.json to the repository, put the two keys in the
repository's secrets, and let the runner do the rest:
name: Monthly AI visibility check
on:
schedule:
- cron: "0 9 1 * *" # 09:00 UTC on the 1st
workflow_dispatch:
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npx saylent verify ./example.com/2026-09-14/run.json --yes --max-usd 2
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- uses: actions/upload-artifact@v4
with:
name: movement
path: example.com/*/movement.htmlEnvironment variables are the first place saylent looks for keys, ahead of a
.env file and ahead of ~/.saylent/config.json, so secrets passed in env:
are enough. This is a different job from the
GitHub Action: that one is the $0, no-keys
gate-check, and it belongs on every push. This one spends real credits, so
put it on a schedule you chose.
What to expect from a scheduled job
Each run writes its own dated folder beside the baseline's, and
saylent history lists them in order - see
Verify and history.
Two things differ once nobody is watching:
- Exit code
2means an engine failed, not that the run failed. The movement report is still written. In CI that fails the step, so decide deliberately whether you want that. - Upgrading the CLI can make verify refuse to run, on purpose, if the
shipped question templates changed since your baseline was frozen. Pin the
version in the job (
npx saylent@0.1.1), or re-baseline with a freshsaylent auditwhen you upgrade.
When to move to the app instead
A folder of run bundles is real history, and for one brand checked on a schedule it is enough. Deploy the app when you want several brands and several people on one deployment, a fix tracker that spans runs instead of one report at a time, share links for a client, a spend cap that holds across everyone, or scheduled runs with nowhere to keep a runner.