🟡 CI for facts

You get: a build that fails when your landing page lies. Pairs with: a weekly GitHub Action and marketing’s forgiveness.

tabstack generate json https://yoursite.com 
  --instructions "List every quantitative claim on this page — numbers, counts, latencies — with its exact text." 
  --schema '{"type":"object","properties":{"claims":{"type":"array","items":{
    "type":"object","properties":{"text":{"type":"string"},"value":{"type":"number"}}}}}}' 
  | jq -e '.claims | length > 0'

The idea

“Trusted by 500+ teams.” “Sub-100ms p99.” “99.9% uptime.” Marketing pages are full of numbers that were true when someone wrote them and drift quietly after.

This recipe extracts every quantitative claim from your landing page as structured data. Add it to CI and you can assert those claims against real data, fail the build when they’re wrong, and catch content rot the same way you’d catch a broken test.

GitHub Action

name: Fact-check landing page
on:
  schedule:
    - cron: '0 9 * * 1'   # Monday mornings
  workflow_dispatch:

jobs:
  fact-check:
    runs-on: ubuntu-latest
    steps:
      - name: Extract claims
        env:
          TABSTACK_API_KEY: ${{ secrets.TABSTACK_API_KEY }}
        run: |
          tabstack generate json https://yoursite.com             --instructions "List every quantitative claim with its exact text and numeric value."             --schema '{"type":"object","properties":{"claims":{"type":"array","items":{
              "type":"object","properties":{"text":{"type":"string"},"value":{"type":"number"}}}}}}'             > claims.json

          echo "Claims found:"
          cat claims.json | jq -r '.claims[] | "  • (.text)"'

      - name: Verify customer count
        run: |
          # Example: assert the "500+ teams" claim against your real DB count
          CLAIMED=$(cat claims.json | jq '.claims[] | select(.text | test("teams")) | .value')
          ACTUAL=$(curl -s https://api.yoursite.com/stats | jq .customer_count)

          if [ "$ACTUAL" -lt "$CLAIMED" ]; then
            echo "❌ Landing page claims $CLAIMED teams but DB shows $ACTUAL"
            exit 1
          fi

Simpler version — just detect claim drift

If you don’t have an API to compare against, at least detect when the page changes:

# Save a snapshot
tabstack generate json https://yoursite.com 
  --instructions "List all quantitative claims." 
  --schema '{"type":"object","properties":{"claims":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string"}}}}}}' 
  | jq -r '.claims[].text' | sort > claims-snapshot.txt

# In CI: compare against the snapshot
tabstack generate json https://yoursite.com 
  --instructions "List all quantitative claims." 
  --schema '{"type":"object","properties":{"claims":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string"}}}}}}' 
  | jq -r '.claims[].text' | sort > claims-current.txt

diff claims-snapshot.txt claims-current.txt || echo "Claims changed — review manually"

Why generate not extract

extract json structures what’s on the page literally. generate json reasons about it with your instructions — in this case, identifying which text elements are making quantitative claims, even when they’re phrased as “more than 500” or “over 10,000”. The instruction “list every quantitative claim” applies semantic judgment that pure extraction can’t.