The GoToMesh mental models
GoToMesh has a handful of ideas you have to hold in your head to drive it well. None of them is hard, but a few are subtle enough that people build the wrong picture and then fight the tool. This page lays out the six that matter, each as what it is / why it matters / how to drive it.
If a term is unfamiliar, the glossary defines it. The step-by-step “which file, in what order” lives in Lifecycle and Tuning — this page is the model, not the procedure.
1. Site type (kind)
What it is
Every mesh declares one kind in gtmesh.config.yaml. It is one of three:
kind | What it describes |
|---|---|
non_commercial | Content hubs discovered from search demand: hubs plus spokes (the bundled demo). |
commercial_catalog | Many product / category pages plus an order action; clusters group them. |
commercial_pages | A few core service / product landings that content funnels up into. |
Why it matters
kind fixes the authority topology — the shape of how pages point at each other and which pages are the destinations. Everything about tiering (which pages are conversion pages, which are feeders, which are leaf spokes) follows from it. It is the very first thing project discovery establishes — the first interview question — because the rest of the structure is built on top of the answer.
How to drive it
Set it once, early. With the bundled scaffold it is kind: non_commercial. If you bootstrap with discovery (gtmesh discover → the discovery skill → gtmesh init --from-discovery), the skill picks the kind for you and overlays it onto the config. You generally do not flip kind later — it is a structural decision, not a knob. See the discovery contract for how discovery establishes it.
2. The authority layer
What it is
Two fields describe where a page sits in the authority topology:
tier—A(conversion, the money pages, where authority converges),B(feeder pages that funnel up to A),D(spoke / leaf, e.g. glossary and educational pages).role—hub,sub-hub, orspoke.
These are assigned by matching each keyword against reference/signals.csv — a keyword → role / tier rule table. The engine never guesses tier or role; it reads it from your signals.
Then there are two different ways a page can enter the mesh, and conflating them is the single most common mistake:
seeds/<class>.csv | reference/seed-pages.csv | |
|---|---|---|
| What a row is | A candidate TERM — a real keyword that has search demand behind it | A source-less APEX page — a hub / landing with no keyword data behind it |
| Where it comes from | The harvest skill, ranked against a demand corpus | You (or discovery), declared by hand |
| Carries metrics? | Metrics are joined later from data/raw/ (the file itself never holds Vol/KD) | None — there is no keyword to measure |
| On the calendar? | Yes — it is scored and scheduled like any keyword | No — off-calendar; it exists because the topology needs it, not because demand ranked it |
This is the bit people get wrong. seeds/<class>.csv is a list of terms with demand — things people search for, that you want to rank for, scored and queued by opportunity. reference/seed-pages.csv is a list of pages you decree into existence — the converging hubs and commercial landings the whole mesh points at, which have no search query behind them and so are never volume-ranked. One is “what should we write because people are searching for it”; the other is “what must exist because it is the destination.”
Why it matters
The authority layer is what stops the mesh from being a flat pile of pages. Tier and role decide which pages link up to which, and the apex pages in seed-pages.csv are the things everything else funnels toward. If you put a destination page into seeds/<class>.csv it would get scored on (non-existent) keyword volume and probably never get built; if you put a demand keyword into seed-pages.csv you would lose its keyword data and its scoring entirely.
How to drive it
- Tune keyword → role / tier classification in
reference/signals.csv. - Add apex / pillar pages (the destinations) to
reference/seed-pages.csv. - Fill demand-driven term classes with the
harvestskill, which writesseeds/<class>.csvfor your review.
Deeper procedure is in Tuning.
3. Slug anchoring, freeze, and rename
What it is
A page’s slug names its HEAD keyword — the volume-ranked primary keyword for that page (set by identity: { anchor: head } in the config), not a divergent source parent_topic. The important property: once a slug is committed, it is frozen. It becomes sticky registry state.
So what changes a URL, and what doesn’t:
| Event | Does the URL move? |
|---|---|
| The head keyword flips on a re-extract (a higher-volume keyword takes the lead) | No. The committed slug stays put — no URL churn. |
The source parent_topic changes | Triggers a redirect action (human-gated). |
A rename group-edit in overrides/group-edits.yaml | Yes — this is the deliberate lever. |
Why it matters
URLs are expensive to change — they break links and rankings. If the slug followed the head keyword on every re-extract, your URLs would churn every time the keyword tool reshuffled volumes. Freezing the slug means the catalogue can keep refreshing keyword data underneath a page without ever moving its address by accident.
How to drive it
The only lever that intentionally moves a committed URL is a rename group-edit in overrides/group-edits.yaml. A rename:
- pins the new slug,
- keeps the page’s identity (it is the same page),
- emits a 301 redirect (appended to the durable
registry/redirects.csvledger, which old URLs resolve through forever), - and moves the page bundle (the written body and its co-located assets) to the new path.
So: re-extracts never move a URL; only an explicit rename does. The full slug-change / removal detail is in Lifecycle.
4. The SERP layer model
What it is
Some pages carry a funnel value describing the SERP layer they belong to — what the search results for that query actually look like:
commercial— the SERP is dominated by landing / product pages (this query is a money page).content— the SERP is informational; this page funnels up into a commercial landing (viafunnel_target, a slug orparent_topic).mixed— the SERP is split roughly 50/50; a human call, never auto-resolved.
funnel_target names the landing a content row links up to. Both are frozen discovery decisions — discovery classifies them once (by tearing down the real SERP with gtmesh research serp) and the engine simply applies them. It does not re-derive the layer on every plan.
Why it matters
This is how money pages avoid being buried behind blog posts. A commercial-layer landing ships off-calendar, by business priority — it is exempt from volume scoring (see scoring.exempt with when: { funnel: commercial } in the config). Without this, a high-value landing page with modest search volume would queue behind a pile of higher-volume informational articles and never get built. The SERP layer says: this is a destination, ship it because the business needs it, not because a volume number ranked it.
How to drive it
You normally don’t set funnel by hand — discovery establishes it from the SERP teardown and writes it into seeds/<class>.csv / reference/seed-pages.csv. The lever you do hold is scoring.exempt in gtmesh.config.yaml, which is what makes the whole commercial layer ship off-calendar. (On a non_commercial mesh nothing carries funnel: commercial, so the rule is inert.) See the discovery contract.
5. Fan-out vs fragmentation
What it is
One parent_topic can legitimately fan out into several typed pages — a glossary entry and a guide for the same term, for example. That is a feature: different page types serve different intents for the same topic.
Fragmentation is the failure mode: a single stray keyword minting a junk extra page that nobody needs.
The guard between them is classification.min_group_members (with a companion, min_group_volume_pct) in gtmesh.config.yaml. A typed sibling group must clear either bar to spawn its own page — at least min_group_members members, or at least min_group_volume_pct of the parent’s volume. If it clears neither, it folds back into the parent’s dominant page as brief material instead of becoming its own page.
# gtmesh.config.yaml → classification
# min_group_members: 2 # default 1 = off; set 2 to fold single-member fragments
# min_group_volume_pct: 10Why it matters
Programmatic content lives or dies on this line. Fan-out gives you good coverage (a term explained in a glossary and walked through in a guide); fragmentation gives you thin, near-duplicate pages that dilute the mesh and look like spam. The guard lets you keep the first and stop the second.
How to drive it
The default is min_group_members: 1, which is a no-op (every group spawns). Set it to 2 to fold single-member fragments back into their parent. Tune min_group_volume_pct alongside it if you’d rather gate on share-of-volume. Watch the plan’s output as you change it. More in Tuning.
6. The invariants
What it is
A short list of properties GoToMesh guarantees and will not break:
- The CLI is deterministic and LLM-free. Same inputs → byte-identical registry. The only step that uses a model is the
article-writerskill, which writes page bodies. - The committed registry IS the state file.
registry/pages.csvis master state — never hand-edited.apply,seal, and the lifecycle commands are its only writers. planis read-only. It computes the diff and prints it; it writes only a derived, git-ignored planfile. It never changes state.- Discovery is
import, notplan. The open-ended, networked research (thediscoveryandharvestskills) runs outside the deterministic loop and emits committed, human-reviewed files. The engine then consumes those files deterministically.
Why it matters
These are the reasons you can trust the mesh: re-running apply is always safe, the diff is reviewable because state is a committed file, and the one non-deterministic, model-driven step (writing prose) is firewalled off from the structural engine. The boundary between “the deterministic engine” and “the model-driven writer / researcher” is the whole design.
How to drive it
You don’t drive the invariants — you rely on them. Concretely: never hand-edit registry/pages.csv; use plan freely (it costs nothing and changes nothing); and treat the files discovery / harvest write as input you review and commit, not as engine state. The lifecycle that flows from these rules is in Lifecycle.