Glossary
One crisp definition per term. Where a term has a fuller treatment elsewhere, the definition links to it. Terms are alphabetised.
AEO / citability gate — the quality check that scores a drafted page on how
likely AI answer engines are to cite it (AEO = Answer Engine Optimisation). The
engine-owned review-gate skill knows how to score; the numbers
(weighted dimensions, thresholds, answer-block length) are tuned in
gtmesh.config.yaml under aeo:. A page passes only when every dimension
clears its bar, the weighted overall clears overall_threshold, and there are
no blockers.
apply — the command that makes reality (the committed graph plus the page
files) match desired state. Idempotent and Terraform-style: it previews what it
will do and prompts to confirm (--yes skips). It only acts when there’s a
difference, so it’s always safe to re-run. apply, seal, and the lifecycle
commands are the only writers of the graph.
article-writer — the repo-local skill that fills page bodies (and the
editorial meta fields). The one and only step where a model runs. It reads a
page’s _brief, schema stubs, templates, and foundation (where brand.md
carries the strategic “why”); fills the content; runs the humanizer and gtmesh page validate; then invokes
the review-gate. It never touches the slug, the mesh links, or
the committed graph.
the bag — the data/raw/ directory: immutable, timestamped keyword/search
exports written by pull. plan reads the frozen bag and never
re-fetches, so a plan is reproducible from committed data.
built hashes — the provenance hashes seal stamps onto a built page:
built_brief_hash, built_schema_hash, and body_hash. They record what a
page was built from, which is what makes later diffs precise (the engine can
tell exactly what changed). There’s no projection hash — the projection
re-derives into site.manifest.json, so there’s nothing to stamp. See also brief_hash.
catalogue — a reconcile action: a brand-new identity is recorded in the graph with no page created yet, because it isn’t promoted to an actionable status. (Contrast create.)
catalogue loop vs production loop — the two rhythms GoToMesh runs in. The
catalogue loop (pull → plan → apply) is cheap and automatic: it keeps
the map of everything that could exist in sync, and is safe to schedule. The
production loop (promote → apply → write → seal → publish) is deliberate:
it decides which catalogued pages to actually build, then builds, reviews,
and ships them. promote is the gate between the two.
axis — a single-valued domain axis, declared under taxonomy.axes:
an entity-valued axis like category (crm, messaging, payments — what the page
is about), left open (category: []) because its values are entities validated
against the entity nodes in the graph. A page relates to its value through a
HAS_<AXIS> edge — the same edge a facet uses; the only difference is that an
axis declared here carries one value per page. These axes drive sibling links
and are authority-bearing (a page rolls up to its axis hub). See facet, domain
relationship, and the mental models.
domain relationship — a page’s HAS_<AXIS> edge to a domain value: the
factual substrate (“this pump is a rotary lobe pump, made by Alfa Laval”). It is
the one place a page’s domain facts live — Page.edges carries that edge set
itself ({ type, to } with real node ids), on the committed side and the desired
side alike. The target is the value’s owner hub where one exists (an owned
value and its hub are the same graph node), else a bare <axis>/<value> node.
Contrast the topical relationships (MEMBER_OF/HUB_OF/PILLAR_OF), which
ride the same Page.edges but carry authority rather than facts.
cluster vs axis — say which layer you mean
“Cluster” names the authority layer, and only that. Say the specific one:
- topic — a
topics/<value>node: the authority unit. Pages areMEMBER_OFit; its apex (HUB_OF/PILLAR_OF) is where authority pools. This is what people mean by “a cluster of pages”, and the only thing “cluster” means in gtmesh. - root topic — a topic that is also a pull frontier: it carries
seed_terms, sopullrefreshes its demand every cycle. Rootship is a pull decision, orthogonal to authority. - domain axis (config
taxonomy.axes/taxonomy.facets) — the factual layer, not the authority one: an axis declaration naming a single-valued axis (category,manufacturer) or a many-valued one. Both produce the sameHAS_<AXIS>edge; only cardinality differs. In practice these axes are the entity kinds whose values get topic hubs — which is how the two layers meet, and why keeping the words apart matters (#371).
A page’s domain relationships are its HAS_<AXIS> edges — that and only that. A page’s topical
membership is a separate layer (MEMBER_OF). Both ride Page.edges, so you select on either by naming what
it points at: --has <id> (or --has <axis> for the whole axis) for the domain layer, --topic <value> for
the topical one.
content-types package — the workspace TypeScript package gtmesh types
emits (default packages/content-types/) for an SSG or other consumer to
compile against. It carries generated per-type page interfaces plus the
graph-native readers (loadGraph(), loadManifest(), page loaders).
gtmesh types --check is the CI gate against drift.
brief — the writer’s content spec: identity + demand + the content-determining
columns folded in + the resolved entity’s grounding facts (name, source_url,
notes, aliases). It is surfaced verbatim as the page’s _brief block, so the
writer reads exactly what the hash gate covers. The block is derived, not
authored: every gtmesh apply re-bakes it wherever it drifted from the node, so
new demand reaches the writer (the body is untouched — body_hash excludes
_brief). See brief_hash.
brief_hash — the canonical hash of the brief: the body inputs (primary
and secondary keywords, intent, section, template, content-determining
columns) plus the folded entity facts. Changing any of them rewrites the body
(so a changed fact now correctly rewrites the prose). Its built_brief_hash
variant is stamped at seal. A projection change (slug, mesh links, cards) is
not hashed — it re-derives into site.manifest.json with no
rewrite. (brief_hash was named content_hash before the graph model.)
create — a reconcile action: a brand-new identity
that is already promoted to an actionable status (queued/writing/
needs_update) gets its page scaffolded and moves to writing. (Contrast
catalogue.)
demand fold — with entity-aware classification on, the mechanic by which a
source-less seed hub absorbs its demand cluster (head keyword, secondaries,
summed volume) instead of a competing page being minted. It fires only when the
classified demand produces the seed’s exact identity — the same
parent_topic (the entity’s slug), page_type, and an empty
discriminator. See Folding demand into a
hub.
desired state — what the committed graph should be, computed by plan
from your inputs (config, reference tables, seeds, the bag). apply makes
actual state match it. This is the central idea: the graph is the desired
state, the plan is the diff against it, and Git is the audit log. See the
mental models.
discovery — the research that establishes a mesh’s shape. After gtmesh init
scaffolds the repo, the repo-local operator skill interviews you, validates
demand, and builds the structure (config + reference tables) through the
deterministic CLI verbs. It runs outside the deterministic loop — the engine only
consumes the committed files it produces. See the
walkthrough.
discriminator — one of the composite identity keys:
the field that distinguishes two pages that would otherwise collide on the same
parent_topic and page_type. It keeps each identity unique. A split sets it
from each page’s primary_keyword; under entity-aware classification a
sections_map rule can pin it via then.discriminator so synonyms collapse to
one sub-page.
drift — a page that has fallen behind the graph since it was built. gtmesh status
counts it in two shapes, because they have two different fixes. Content drift
(brief_hash moved) means the page’s assignment changed after the prose was
written — fresh demand, a changed entity fact. If the body still answers the brief,
gtmesh page amend → seal → publish re-stamps it; if the assignment really moved,
gtmesh page recreate hands it back to the writer. Schema drift
(current_schema_hash moved) means the page type’s shape changed; gtmesh apply
re-validates each body, restamps the ones that still fit, and hands the rest back
to the writer as needs_update. gtmesh doctor’s built-drift check names the
pages and the verb. The render projection is not drift: links re-resolve into
site.manifest.json on every build, so a projection change is a manifest diff
with no page action. See
Lifecycle & reconcile.
entity node — how you author an entity: a node carrying
domain labels (its class + any domain axes) and fact props (name,
source_url, aliases, specs), written with gtmesh graph upsert <id> --label <class> --prop name=…. Used in classification and to group siblings (e.g. brand
hubs sibling with same-class brands). Read back with gtmesh graph get <id>;
when the node also becomes a page its facts fold into the _brief. Entities live in
the committed graph — the engine reconstructs the entities table straight from it (there
is no reference/entities.csv); the operator skill drives bulk authoring for you.
entity / entities — a real-world thing the content is about (a brand, a product, a category) rather than a keyword string. Semantic SEO optimises for entities, not exact-match strings; GoToMesh resolves a keyword to its entity via the entity nodes in the graph, and the highest-priority class wins when several match.
entity-aware classification — an opt-in classification mode
(classification.entity_aware) that consolidates all spellings and phrasings of a
known entity under its canonical hub: the brand forms are stripped from each
keyword and the remainder is classified (empty → the hub; an intent → a nested
sub-page). Off by default; see Tuning.
pull — the command that pulls keyword/search signals into
the bag (data/raw/). A cluster pull runs two pulls (matching-terms
and questions) and expands a seed into many related keywords; --source seeds
refreshes a curated term list’s metrics without expansion. Exports are immutable
and timestamped.
facet — a many-valued domain axis, declared under taxonomy.facets. A
product can relate to many values at once — several applications, several
industries — so it carries one HAS_<AXIS> edge per value. That is the only
difference from a cluster: same edge, riding the same Page.edges, different
cardinality. A facet axis is not weighted for up-links by default (that would
dilute authority convergence), so the SSG typically aggregates it into facet →
member lists at build time. gtmesh page validate/doctor cross-checks every facet
value names a real entity. See Tuning.
freeze (slug) — see slug anchor (head) & freeze.
funnel_target — for a page whose SERP layer is content, the
landing it funnels up into (named by slug or parent_topic). It’s the edge
from an informational page to the commercial page it supports. Set as a frozen
discovery decision alongside funnel; inert on a non-commercial mesh.
GoToMesh — the product: a deterministic, self-refreshing programmatic-content mesh engine. The name is a play on go-to-market — it builds your go-to-market as a content mesh. gtmesh is its command-line tool.
harvest — the engine-owned skill that figures out what pages should fill an
entity class (a glossary especially) from demand signals: it brainstorms
candidates per taxonomy family, ranks them against a demand corpus, validates
demand via Ahrefs, scores the cut, writes a curated term list to
seeds/<class>.csv (terms + provenance, never metrics), then stops for
human review. Configured under discovery: in gtmesh.config.yaml.
pillar / hub / sub-hub / spoke — the four roles in the authority topology of a
topic cluster. The role itself is derived from
the graph edges, not stamped: a PILLAR_OF edge makes a page a pillar, HUB_OF a
hub (a sub-hub if it’s also a member of a higher owned topic), else a spoke — so
authoring the apex edge is the promotion. Links between them are derived the same way.
With a worked example (a pump catalogue):
- hub — the navigational / commercial centre of a subject: the catalogue or
conversion page breadcrumbs run through. e.g.
/categories/rotary-lobe-pumps(or a brand page/manufacturers/alfa-laval). It’s an up-link target, but it stays the archive layer — it doesn’t hoard in-content weight. - pillar — the informational convergence vertex: the deep “what is X” page that
owns the broad head-term. e.g.
/guides/how-does-a-rotary-lobe-pump-work. When a topic has one, an informational spoke’s up-link prefers it over the hub — pillar and hub are co-apexes, both reachable over the topical graph. Optional — a topic without one just uses its hub. - sub-hub — an intermediate hub beneath the apex. e.g. a manufacturer hub
/manufacturers/alfa-lavalsitting under a/manufacturerssection index. - spoke — a supporting leaf page that links up. e.g. a product
/products/alfa-laval-sru, or a supporting guide.
See The mesh & links for when to pick each and how the pillar and hub relate.
humanizer — the skill that strips AI-writing tells from a draft and pulls it
toward the project’s house voice (foundation/voice.md). The detection patterns
are generic and engine-owned; the target voice is yours. The
article-writer runs it before the review-gate.
identity / identity_keys — a page’s stable identity is a composite key: the
fields in identity_keys (default parent_topic, page_type,
discriminator — and market joins automatically once there’s more than one
market). Two records with the same identity are the same page. Identity is what the
graph diff keys on. See the mental models.
image-director — the skill that generates and places the images a page has
briefed. It reads the page’s art-direction briefs plus foundation/art-direction.md
and the images: config, generates via the image MCP, writes the asset files
into the page bundle, and adds asset: to each slot. Invoked explicitly,
separate from writing.
intent — the single search intent a page serves (e.g. transactional,
commercial, branded, informational). Declared in taxonomy.intents in priority
order; classify picks the first present on a keyword. Semantic SEO’s rule is one
intent per page, which GoToMesh enforces by construction.
kind (site type) — the project’s authority topology, set once in
gtmesh.config.yaml. One of non_commercial (content hubs discovered from
demand), commercial_catalog (many product/category pages plus an order action),
or commercial_pages (a few core landings that content funnels up into).
How authority is arranged follows from it. See the
mental models.
mesh — the whole interlinked set of pages plus the derived link graph
between them. The committed graph is the mesh’s source of truth; links,
redirects and breadcrumbs are all derived from it (into
site.manifest.json) and re-derived on every change.
needs_update — a status: a built page whose body inputs
changed and whose revision hasn’t shipped yet (the old body keeps serving until
it does). Also the status a shipped page re-enters after assets are placed
(gtmesh page amend).
noop — a reconcile action: nothing changed for this identity, so the engine does nothing.
opportunity / effort / winnability — the three numbers that decide which
topics to invest in. A topic folds its head keyword’s demand onto itself, and
from that derives opportunity (the value at stake — total_vol × cpc by
default) and effort (the cost to win — keyword difficulty). Winnability
is the KD-inverse, (100 − difficulty) / 100, on a 0–1 scale. gtmesh topic candidates ranks by opportunity × winnability: the commercial ∩ winnable
intersection, where the commercial half rides inside opportunity (CPC is the
market’s buyer signal — advertisers bid where the money is). Every other topic
view orders by opportunity alone, which flatters big topics you can’t win. All
three formulas are config-tunable (scoring.topic_opportunity /
topic_effort / topic_selection). Winnability is read at the topic level,
not the keyword level: max(head, tail), where head is the head keyword’s own
KD-inverse and tail is the KD-inverse of the median difficulty of the
topic’s uncovered demand. So a hard head is a horizon, not a veto — you
climb the tail and the head comes into reach. See
Winning a topic.
unscored (difficulty) — a keyword the provider returned no difficulty for
(common across the low-volume long tail). gtmesh records it as unknown — an
empty cell in the bag, never 0 — because unscored and uncontested are
opposite claims: collapsing them would make every unrated tail term look
trivially winnable. Shown as KD —. An unscored keyword still counts as
uncovered demand, but never as evidence of an easy way in.
parent_topic — one of the identity keys, and the
legacy slug stem. With slug anchoring set to head,
a page’s URL is named after its head keyword rather than parent_topic, but
identity still keys off parent_topic. A change to it is a rename.
plan — the command that recomputes desired state and shows
the diff against the committed graph. Read-only — it prints the diff and
writes a derived, git-ignored .gtmesh/plan.json, but changes nothing. apply
computes the same diff itself, so plan is an optional preview you run whenever
you want a look.
promote — the intent-based gate that chooses which catalogued pages to
build. It writes only status (e.g. planned → queued), builds nothing, and
is reversible (demote). It selects pages by node fields (section, topic,
domain relationship, page-type, slug prefix, status) or by a graph walk (--under <hub>), and
applies by default (--dry-run previews). It’s the gate between the
catalogue and production loops.
pulls (matching-terms, questions) — the two-pull pattern a cluster pull runs against Ahrefs: matching-terms (the broad keyword expansion) and questions. Both land in the bag.
reconcile actions — the one-action-per-identity verbs plan emits by
diffing desired state against the committed graph. They are: noop
(nothing changed), recompute (an unbuilt page’s inputs changed),
rewrite (a built page’s body inputs changed — pulls the writer back in),
redirect (a slug changed — human-gated, moves the bundle and mints the
url/ALIAS_OF alias), catalogue (record a new identity, no page), and
create (scaffold a new, already-promoted identity). Who acts varies: the
engine handles recompute/catalogue/create; the writer handles rewrite; redirect
is human-gated. A projection-only change (a moved mesh link) is not an
action — it re-derives into site.manifest.json with no
rewrite.
redirects — the durable record of slug changes (old slug → current). Each old
URL becomes a url node with an ALIAS_OF edge to
the live page node, so chains collapse intrinsically (the alias always resolves
to the page’s current slug) and old URLs resolve forever — the SSG emits 301s
from a manifest query. Format + SSG wiring:
Redirects.
graph store / registry — the committed source of truth for every page that
could exist and what state each is in:
graph/nodes.jsonl (LPG nodes) + graph/edges.tsv (typed mesh edges) — the
diffable state file. Never hand-edited; apply, seal and the lifecycle
commands are its only writers. See the
mental models.
rename — moving a page’s URL via an explicit group-edit (or a parent_topic
change). A committed slug is frozen, so only a rename
moves it — firing a 301 and a bundle move, and minting the url/ALIAS_OF
alias (see redirects).
review-gate — the independent, blocking quality reviewer the
article-writer invokes as its final pre-seal step. It scores
AEO/citability and enforces the house voice in one pass,
returning a PASS/FAIL report. On failure the page stays in writing with notes;
on pass it returns control to the writer. It never calls gtmesh page seal.
role — the authority role a page plays — pillar / hub / sub-hub / spoke. It is a
view derived from the graph edges (a PILLAR_OF/HUB_OF edge ⇒ pillar/hub, else
spoke), not a stored column. The signals and an authored apex page (gtmesh page add --role hub|pillar) appoint the role — an ownership decision that makes classify emit
the apex edge — and the role you read back follows from that edge. See the
mental models.
seed / seeds/<class>.csv — a seed is a starting keyword or term that
feeds the pipeline. seeds/<class>.csv is a curated, human-reviewed term list
for an entity class (written by harvest) — terms plus provenance
only, never metrics (Vol/KD live in the bag and refresh on cadence). A
curated term is seed-authoritative: plan keys its identity and routing off the
curated term and the seed’s section/page_type. Distinct from a
seed-page.
seed-page — a source-less page you declare by hand with gtmesh page add
(which writes a source: seed node into the graph) — typically an apex or pillar
hub that no keyword pull would mint on its own. Distinct from a seed (a
keyword/term). See the
mental models.
SERP layer (layer: commercial/content/mixed) — a classification of a keyword’s search results by what’s actually ranking (derived from a SERP teardown). It separates the money layer from the content layer so a commercial page ships by business priority rather than volume. See also funnel_target.
signals.csv — the reference table (reference/signals.csv, keyed by
signal) that maps keyword signals to a role — the input that tunes how
keywords are classified into hubs, pillars and spokes.
slug — a page’s URL path. The only deterministic field in a page’s meta
(apply-owned); the editorial meta fields are writer-authored. Don’t hand-edit
the slug — fix the inputs and re-plan. See the
mental models.
slug anchor (head) & freeze — with identity.anchor: head, a page’s URL is
named after its head keyword (the volume-ranked primary), not a divergent
parent_topic. The head can flip on re-pull, so a committed slug is
frozen (sticky committed state): only an explicit rename
group-edit moves it (firing a 301 and bundle-move). Identity stays
parent_topic either way.
status lifecycle — the states a page’s status moves through:
planned (catalogued, not authorised) → backlog → queued (promoted to
build) → writing (page scaffolded, awaiting a body) → review (sealed) →
published (live), plus needs_update (a built page whose inputs changed).
Status moves are deliberate human edits (via promote/demote/seal/
publish), separate from the input-driven reconcile actions.
symbolic ref — how prose links to another page in the mesh: by stable
identity, not by URL. Two forms: ref:page/<id> links a specific page by its
unique graph id (survives a rename), and ref:links/<scope>/<n> is
self-relative — the current page’s Nth link in a scope (up = its published
up-links, down = its children, siblings, across). gtmesh build bakes an
id→slug table into site.manifest.json (refs) and the per-page link arrays live
in pages; the SSG substitutes each token for the live URL at render. The point is
re-resolution: ref:links/up/0 (“my primary parent”) re-resolves when a new
hub takes that slot, and ref:page/<id> follows a rename — a hardcoded URL would
rot silently (no redirect). A literal internal URL in a body is therefore a
validate error, as is a ref that doesn’t resolve (an unknown page id, or a
ref:links index out of range). External links are written as normal URLs.
topic & apex — a topic (topics/<value>) is the unit of authority: the subject a
set of pages is about. Pages join it with a MEMBER_OF edge; exactly one — its apex —
owns it with a HUB_OF or PILLAR_OF edge, and members route their up-links there. (A
topic may carry both a commercial hub and an informational pillar as co-apexes.) An
apex edge implies membership, so an owner carries no self-MEMBER_OF. Topics are minted
by ownership: an appointed apex (a signals.csv role rule, or gtmesh page add --role)
mints the topic for the value it owns, and gtmesh topic authors them directly. See
The mesh & links.
up-link resolution — how the engine turns a page’s up: hub_of(entity) rule
into an actual parent: it links to the hub of the page’s own resolved entity
sitting above it in the authority flow; else an entity-less landing that
shares a cluster value; else the apex. A shared cluster alone never reaches a
different entity’s hub (a cross-entity guard). See the mesh &
links.