Skip to Content

The refresh loop

Once the registry exists you don’t bootstrap again — you change an input and reconcile. In steady state that’s a three-command rhythm:

gtmesh extract --cluster slack # newer data → a newer export in the bag gtmesh plan # see the diff (printed to stdout) gtmesh apply # enact it (idempotent)

That’s the whole loop. The rest of this page explains why each step behaves the way it does — and why you can run the cheap part of it on a schedule without worrying.

The three commands

extract — refresh the data

gtmesh extract pulls newer keyword/search data and writes it to the bag (data/raw/). Each export is immutable and timestamped — extract never overwrites an old pull, it adds a newer one beside it. So the bag is a growing pile of dated snapshots, not a single mutable file.

gtmesh extract --cluster slack --dry-run # report the planned pulls, spend no credits gtmesh extract --cluster slack # the real pull → data/raw/keywords/ahrefs/ gtmesh extract # all configured seed clusters

plan — preview the diff

gtmesh plan reads the frozen bag and computes what the registry should become. It picks the newest snapshot for each keyword (this is the “recency” behaviour — your latest pull wins) and shows you the diff against the committed registry.

plan is read-only and free. It prints to stdout and writes a derived, git-ignored .gtmesh/plan.json — it never re-fetches data and never changes the registry. Run it whenever you want a look; re-run it as many times as you like.

gtmesh plan # prints the plan to stdout gtmesh plan > plan.md # keep the rendered plan in a file gtmesh plan --json | jq . # machine output

apply — enact it

gtmesh apply makes the registry (and the page files) match what plan showed. It’s idempotent: it only acts where there’s a real difference, so running it twice in a row does nothing the second time. Terraform-style, it previews what it will do and prompts to confirm.

gtmesh apply # shows the intended actions, prompts to confirm, then enacts gtmesh apply --yes # skip the prompt (scripts/CI; required in a non-interactive shell)

You never need plan between an extract and an applyapply computes the same diff itself. plan is the optional preview; apply is the one that writes.

Why the bag is frozen and timestamped

Because extract appends dated snapshots and plan reads the frozen bag, the loop is deterministic and auditable:

  • A given bag always produces the same plan — re-running plan can’t surprise you with different numbers, because the data it reads doesn’t move.
  • The keyword history is preserved. You can see how volume or difficulty drifted over time, and old pulls are never silently lost.
  • plan never spends API credits. The only command that talks to a provider is extract.

Re-extract cadence

How often you re-extract is your call — keyword metrics drift slowly, so most operators pull on a schedule (weekly or monthly) rather than constantly. The key safety property: the catalogue loop is safe to run on a schedule. extract → plan → apply keeps the map of everything that could exist in sync, and because apply only acts on real differences, an automated nightly or weekly run is harmless when nothing changed.

What it is not is an automatic content factory. Re-extracting and applying keeps the catalogue current; it never writes or rewrites a page body on its own. Which catalogued pages you actually build stays a deliberate, human-gated choice — see lifecycle & reconcile.

Editing an input shows recompute

When you edit a reference/ table, a seed list, or a config rule, the catalogued-but-unbuilt rows your edit touches show up in the plan as recompute (with reason: inputs-changed). That’s the signal your edit took effectapply will recompute those rows.

This is deliberate. Without it, an edit to an unbuilt row used to read as noop, which made it look like your change did nothing. recompute tells you the difference was registered and is waiting to be applied.

For exactly what every kind of edit triggers on every kind of row — and who acts on it — see lifecycle & reconcile.

Last updated on