GEO Loop Skill
One wake-up = one bounded unit of work. This skill governs loop mode only;
one-shot /geo <url> is unchanged and needs no workspace.
Non-negotiables
- Never write to the eGEOagents repo tree. Every write goes to the
workspace resolved from
$EGEO_HOME(default~/.egeo/). - One unit of work per run. Take the domain's
## Current focus, or the first Backlog item if focus is already satisfied. Do not batch. - Exactly one Timeline entry and exactly one LOG.md line per run.
- Write, then verify. Re-read every file you wrote before exiting.
- Never fabricate. Rankings, competitors, and metrics come from collector
JSONL under
data/or from a tool call in this session. A claim you cannot cite isconfidence: lowwith the uncertainty stated in the body. - Append-only history. Never edit or delete an existing Timeline entry or LOG line.
Procedure
1. Resolve the plan
egeo loop run <domain> --dry-run
This is the source of truth for the run: it prints the charter's current focus,
the backlog, collector records added since the last Timeline entry, and
candidate signals. It writes nothing. Use --json when you want to parse it.
If it exits non-zero, stop and report — the workspace or the domain charter is
not in a runnable state (egeo loop doctor explains why).
2. Read the state
$EGEO_HOME/domains/<domain>/README.md— charter, cadence, focus, backlog, Timeline (the last entry tells you where the previous run stopped).$EGEO_HOME/project.yaml— when present, the validated project identity, canonical domain, tracked queries/pages, and anti-spam/canibalization guardrails.egeo loop doctoris the source of truth for its validity.$EGEO_HOME/data/<collector>/*.jsonl— fresh ground truth.$EGEO_HOME/signals/and$EGEO_HOME/docs/— what is already known, so you dedupe instead of duplicating.$EGEO_HOME/config.yaml— models, budgets,reflect.auto_apply.$EGEO_HOME/data/outcomes/ledger.jsonl— append-only decision outcomes whenegeo loop decidehas run.
3. Do the work
Pick the single unit of work and execute it with the existing GEO capability —
the content-scoring, competitive-analysis, and schema-generator skills and
the geo-* agents all apply unchanged. Typical units:
| Situation in the plan | Unit of work |
|---|---|
| A target URL moved ≥3 positions | Write/update a signal explaining the move |
| Target absent from top 10 repeatedly | Signal + a doc proposing the fix |
A tracked page's content_hash changed |
Signal describing what changed |
| A tracked page has no JSON-LD | Doc with copy-paste JSON-LD for that page |
| No fresh data at all | Outcome no-op — do not invent work |
Ranking positions from data/serp/ are ground truth. Any simulated ranking
you produce yourself is confidence: low and must say so in the body.
4. Write artifacts (SUBSTRATE.md)
SUBSTRATE.md in the repo root is the binding contract. In short:
signals/<slug>.md— evidence.docs/<slug>.md— durable knowledge. Kebab-case filenames, English content,kinddecides the folder.- Frontmatter on line 1:
kind,domains(existing dirs underdomains/),created,updated,confidence,sources, plusfrequencyon signals.sourcesmay be empty only whenconfidence: low. - Dedupe (§4): re-observed evidence does not get a new file. On the
existing signal, increment
frequency, setupdatedto today, and append one dated Timeline entry. - Body above
## Timeline= what is true now (rewrite freely).## Timeline= append-only, newest at the bottom. - Docs cite signals and repo paths; signals cite collector JSONL lines
(
data/serp/example-com.jsonl#L42).
5. Close the run
Append to $EGEO_HOME/domains/<domain>/README.md, at the very bottom:
### 2026-07-24 run
Checked serp deltas for example.com; pricing page dropped 3 → 7 for
"best geo tool". Wrote signals/example-com-pricing-drop.md.
Outcome: success
Outcome: is the last line and one of success, partial, failure, no-op.
Then append exactly one line to $EGEO_HOME/LOG.md:
2026-07-24T18:20Z [example-com] run: wrote signals/example-com-pricing-drop.md, outcome=success
Grammar (SUBSTRATE.md §7): <YYYY-MM-DDTHH:MMZ> [<domain>] <event>: <summary>,
UTC minute precision, appended at the bottom, summary ending in
outcome=<class>.
Keep ## Current focus accurate: if the focus item is done, promote the next
Backlog item and remove it from the Backlog.
6. Verify, then exit
python -m egeo.substrate_lint # defaults to $EGEO_HOME
egeo loop doctor
Re-read the domain README and the tail of LOG.md to confirm your two
appends landed exactly once. Fix violations before exiting; a run that leaves
the substrate invalid is Outcome: failure.
Report to the user in three lines: unit of work, artifacts written, outcome.
Collectors
Collectors are deterministic and LLM-free; run them before a loop run when the plan shows no fresh data:
egeo loop collect serp --query "best geo tool" --target-domain example.com
egeo loop collect page --url https://example.com/pricing
serp needs BRAVE_API_KEY; both honour the daily budgets in config.yaml and
fail loudly rather than writing partial records. See collectors/README.md for
the contract.
Common mistakes
- Writing into the repo
prompts/,geo-output/, orsignals/instead of$EGEO_HOME— loop state never lives in the repo. - Two Timeline entries (or two LOG lines) for one run.
- A new signal file for evidence that already has one (use
frequency). - Claiming a competitor ranking without a
data/serp/line to cite. - Doing three units of work because the data looked interesting. One.