Skip to main content

geoctl

Status: v0.1 implemented, weights still provisional. Every command below works and the test suite runs offline with no API key. The 6 scored checks are calibrated against 38 local fixtures (docs/CALIBRATION.md); the weights are initial values, not a claim about what any AI product rewards.

geoctl — Generative Engine Optimization control. An open-source CLI that tells you whether AI systems can reach, read, and correctly answer questions from your website, and helps you fix what's broken. Bring your own LLM keys. Runs locally or in CI. No account, no server.

On the name. geoctl was chosen after a collision check found the earlier working name (geoprobe) unusable: taken on PyPI by an unrelated project, and in active use by a commercial product at geoprobe.ai. geoctl is free on PyPI, npm, and GitHub. The expansion is spelled out above because "geo" alone reads as geospatial to many developers. See #4.

Why this exists

Most GEO/AEO tools count artifacts — robots.txt rules, llms.txt, JSON-LD, sitemap — and roll them into a 0–100 score. There are a dozen good open-source tools that already do that, well. geoctl deliberately keeps only the checks that are specific to AI crawler access, and spends its effort on the part that isn't commodity:

The answerability eval. Give an LLM only what a retrieval-style text crawler would extract from your page — chunked, embedded, top-k retrieved, not the whole document pasted in — then ask it questions a real visitor would ask, and measure how many it gets right, with variance and with context recall reported separately.

That distinction matters. If you hand a frontier model the entire cleaned page, you are measuring whether the model is smart, not whether your site is retrievable. Retrieving the right span is the actual failure mode for AI answers, so the eval measures it.

Install

uvx geoctl audit https://example.com     # one-off, no install
pipx install geoctl                      # installed
geoctl audit https://example.com

Optional JS rendering (adds Playwright):

pipx install "geoctl[render]"

Quickstart

A report with no API key takes well under two minutes:

geoctl audit https://example.com
geoctl 0.1.0 · https://example.com · 10 pages · 4.2s

Deterministic score  40 / 100

  Access        ███████████░░░░░░░░░░░  35/75
  Rendering     █░░░░░░░░░░░░░░░░░░░░░░   4/24
  Discovery     ███████████████████████   1/1

Top findings
  FAIL  REN-001  Only 9% of page text is present without JavaScript.
        /pricing: 412 chars before JS vs 4,380 after (render with --render)
        Fix: server-render or pre-render the pricing content

Measures AI readiness — reach, read, answerability. Not citations or rankings.

Adding the answerability eval, which uses your own key:

export OPENAI_API_KEY=...
geoctl audit https://example.com --eval --judge-model anthropic/claude-sonnet-4-5

The strongest and cheapest eval input is a facts file you write yourself — it is independent of both the crawler view and the rendered view, so it cannot be inflated by extraction luck (ADR-014):

geoctl init                                        # writes geoctl.toml + facts.yaml
$EDITOR facts.yaml
geoctl audit https://example.com --facts facts.yaml

Cost control, because at the defaults this is not a free operation:

geoctl audit https://example.com --dry-run          # estimate only, no API calls
geoctl audit https://example.com --max-cost 0.50   # abort before exceeding

Gate CI. --fail-under is deterministic and always applicable; --fail-under-eval needs an eval and refuses to gate on noise:

geoctl audit https://example.com --fail-under 70
geoctl audit https://example.com --facts facts.yaml --fail-under-eval 70

Other useful commands:

geoctl audit https://example.com --format json --output report.json
geoctl audit https://example.com --render           # needs geoctl[render]
geoctl doctor                                     # check keys, cache, extras
geoctl telemetry show                              # exactly what would be sent
geoctl cache stats

One thing worth knowing before you gate on the eval: at the default 50 questions the 95% confidence interval is about ±14 points, so the threshold gate defaults to a ±15 margin and will decline to fail on a wide interval. To gate more tightly, raise --questions; lowering the margin just fails on noise. The arithmetic is in docs/EVALS.md §4.2.

Full flag reference: docs/CLI_SPEC.md.

What it does and does not measure

It measures readiness and retrievability. It does not measure or promise citations, rankings, or traffic from any AI product. Those depend on retrieval pipelines, ranking, and vendor policy decisions that no local tool can observe. Treat the score as a readiness indicator with published methodology, never as a forecast.

Two scores are reported side by side and are deliberately not blended into one number, so you can always see which signal moved:

  • a deterministic access / rendering / discovery score, and
  • an answerability score with variance, abstention and hallucination rates, and context recall.

Documentation

Document Contents
docs/PRD.md Problem, goals, users, requirements, metrics, risks
docs/ARCHITECTURE.md Stack, module layout, interfaces, data flow
docs/CLI_SPEC.md Commands, flags, config, exit codes
docs/CHECKS.md The scored check catalog and calibration plan
docs/EVALS.md Answerability eval method and limitations
docs/OUTPUT_SCHEMA.md JSON report contract and versioning
docs/TELEMETRY.md Telemetry design and public policy
docs/ROADMAP.md Milestones and exit criteria
docs/DECISIONS.md ADRs
docs/FIXTURES.md Fixture-site coverage spec for calibration
docs/METHODOLOGY.md How the numbers are produced, and their limits
docs/CALIBRATION.md Latest per-check false-positive run
CHANGELOG.md Release notes

Docs site: mkdocs serve (see mkdocs.yml).

Privacy and safety

  • Site content never leaves your machine except to the LLM provider you configured.
  • Telemetry is opt-in, allow-listed, and never contains URLs, page content, file paths, or keys. See docs/TELEMETRY.md.
  • Simulated bot requests send an X-Geoctl-Test: 1 header. Intended for sites you own or have permission to test.
  • Private and loopback addresses are blocked unless you pass --allow-private.
  • API keys are read from the environment only. geoctl refuses to start if it finds key-like values in geoctl.toml, so a credential cannot be committed by accident.

Open core

The CLI is fully capable, not a crippled demo. A hosted tier may sell only things that require a service: scheduled runs, persistent history, alerts, multi-site and team workspaces, managed keys. A feature released in the OSS CLI is never moved to paid.

License

AGPL-3.0-only. It is a free, OSI-approved open source license.

The practical effect: if you fork this and distribute it, or run your modified version as a service, you must offer your source under AGPL-3.0. You cannot take the free CLI, close it, and charge for it. That is the point of choosing it over MIT or Apache-2.0.

It does not stop someone reimplementing the same ideas from scratch — that is a deliberate, accepted limit, and the name is not being trademarked. A fork must rename and cannot pass itself off as geoctl. Reasoning in ADR-004.

Contributing

Contributions are welcome, including first-time ones. See CONTRIBUTING.md — there is a table of ways to help ranked by effort, from reporting a false positive (about 30 minutes) to adding a check. No CLA or DCO sign-off required.

Won't do

  • No guarantees of citations or rankings.
  • No scores presented as comparable across different LLM models.
  • No stealth crawling, IP rotation, or evading bot protection.
  • No collection of site content by telemetry.
  • No feature moved from OSS to paid.

Metadata

Release files for geoctl 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for geoctl 0.1.0
File Size Uploaded
geoctl-0.1.0.tar.gz 97.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for geoctl 0.1.0
File Interpreter ABI Platform
geoctl-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 213.9 kB

Release files / geoctl-0.1.0.tar.gz

Download URL geoctl-0.1.0.tar.gz
Size 97.8 kB
Tags Source
SHA-256 checksum
How to use checksums
eb6a0251bd2b0b0c8f911be1580e851e4e89cfb9dd4da6485fff4920de694bf5
BLAKE2b-256 checksum
How to use checksums
d9db252b34a255b42955245aac072026e86b40d19505235799b07868f4681434
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / geoctl-0.1.0-py3-none-any.whl

Download URL geoctl-0.1.0-py3-none-any.whl
Size 116.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b0dcd2eded63e2d0a161d9fc6f60625c2f3c329e409ea267aed0646a035702ca
BLAKE2b-256 checksum
How to use checksums
598ac92d18e599b7de48bc928d4f62f387a6a1d36fbad419369cdae37fa7602d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page