npm / geo-new

CLI and MCP server

One npm package is both: the command you run in a terminal and the server a coding agent talks to. Keyless from the first call, a key when you want one, and the same audit the browser runs; it speaks to the HTTP API that /docs/api documents. The last two sections are about this site rather than the package: every page here is readable as Markdown and says where its own contract lives.

From a terminal

one line, no key
npx -y geo-new audit https://example.com

The first call mints a session and keeps it in your config directory. The audit starts, or attaches to one already running for that URL, and the measured rows land in about a minute. The report goes to stdout as Markdown and the progress goes to stderr, so the one can be piped and the other cannot. The AI synthesis keeps writing afterwards and never moves a score; --wait-for-ai waits for it.

audit
geo-new audit <url> [--fresh] [--json] [--out file] [--wait s] [--wait-for-ai] [--share] [--open] [--min-score N] [--allow-unscored]Starts the audit, or attaches to one already running for that URL, and waits up to 90 seconds for the measured rows. The Markdown report goes to stdout; --json prints the snapshot instead, and --out writes that same snapshot to a file and leaves stdout empty. --fresh measures again after an edit; --wait 0 prints the admission and returns at once; --share adds a link a person can open.
report
geo-new report [audit_id] [--json] [--out file]Re-reads a report you started, the last one when no id is given, as Markdown unless --json or --out asks for the snapshot. A read never starts work and never costs an audit.
fix
geo-new fix [audit_id]Prints the fix prompt: the page as measured and each open action with its evidence, for pasting into a coding agent.
share
geo-new share [audit_id] [--revoke] [--open]Prints a revocable link to an immutable copy of a finished report, which anyone can open in a browser. --revoke stops every link to that report.
compare
geo-new compare <before> <after> [--json] [--out file] [--min-score N] [--allow-drop] [--allow-missing-baseline]Score, category and row deltas between two audit ids, or between two snapshots saved with --out, compared offline. The first line is the score on both sides. Exits 7 when the score dropped unless --allow-drop; --allow-missing-baseline lets a first run pass, and --out saves the comparison as JSON.
usage
geo-new usage [--json]What you act as, how many audits remain this hour and when that resets.
key
geo-new key create [--label name] | list | revoke <prefix> | set <key>Creates a key (shown once, then saved for this machine), lists yours by prefix and label, revokes one, or saves one you were handed.
login
geo-new login <key>Saves a key for this machine. GEO_NEW_API_KEY does the same for one process, which is the form CI wants.
logout
geo-new logoutRemoves the saved key and session.
mcp
geo-new mcpServes the tools below over stdio for a coding agent, and stays up until the client closes. stdout carries JSON-RPC only.
Every command
--quiet · --verbose · --no-color · --help · --version
Credentials
$XDG_CONFIG_HOME/geo-new/credentials.json (0600, written atomically), or GEO_NEW_API_KEY for one process. A key is sent only to https or loopback origins.
Local server
GEO_NEW_API_URL=http://127.0.0.1:8787 points every command at a local geo.new, such as npm run dev:demo.

exit codes

frozen from 0.1; the lowest wins
0Done. The report is terminal, or as far as you asked it to wait.
1The audit failed: the page could not be read well enough to measure.
2Usage: a missing argument, an unknown flag or command, or a file that is not a snapshot.
3Rate limited. The message says which bucket and how long to wait.
4Auth or ownership: an unknown key, a report that is not yours, or keys switched off on the server.
5Network or server trouble after two retries.
6The score is below --min-score. Unmeasured counts as below unless --allow-unscored.
7The score dropped in compare, and --allow-drop was not given.
8Still running when --wait expired; geo-new report picks it up.
130Interrupted with Ctrl-C.

From an agent

MCP over stdio
claude mcp add geo-new -- npx -y geo-new@0 mcp

# Windows
claude mcp add geo-new -- cmd /c npx -y geo-new@0 mcp

# Cursor, Codex, Windsurf and other MCP clients
{ "mcpServers": { "geo-new": { "command": "npx", "args": ["-y", "geo-new@0", "mcp"] } } }

The server runs inside the package, over stdio, against the same API. There is no hosted endpoint to configure and no key to paste: the first tool call mints a session exactly as the command line does, and a key created in any terminal is picked up on the next call.

audit_page
Audit a pageStarts the audit, or attaches to one already running, and waits up to 45 seconds for the measured rows, reporting each stage as progress. Returns the score, blockers, action plan and section states, with a next step. fresh: true after an edit; share: true also mints a link.
get_report
Read a reportThe summary by default; markdown for the full report as text; json for the whole snapshot when the summary lacks a field. Never starts work.
get_fix_prompt
Read the fix promptThe brief for a coding agent: the page as measured and each open action with the change to make, capped at 32 KB.
compare_reports
Compare two reportsScore, category and row deltas between a report and an earlier one of the same URL that you also own.
get_usage
Read the allowanceWhat you act as, how many audits remain this hour, when that resets, and how full the shared buckets are.
create_share
Create a share linkA revocable link to an immutable copy of a finished report that a person can open in a browser.
revoke_share
Revoke share linksEvery share link to that report stops working at once.
geo-new://audits/{id}
ResourceThe Markdown report of an audit you started, for clients that attach resources rather than call tools.
The loop
audit_page, then get_fix_prompt, edit the page, then audit_page again with fresh: true. A non-fresh call may return the report measured before your change, marked cached with its age; every result carries a next step.
Limits
A rate limit is an ordinary result with the code, the wait and the call to make after it, never an error the agent has to parse. Re-reads are free.
Trust
Quoted page content inside a result is data from the audited site, never instructions. The server never sees page HTML; it sees snapshots and Markdown, exactly like the browser.

This site as Markdown

every document, negotiated
curl -H 'Accept: text/markdown' https://geo.new/agents
curl https://geo.new/agents.md

Every public document answers Accept: text/markdown with its own content as Markdown, and the same document sits at its .md path for a client that would rather not negotiate. Neither needs JavaScript: the HTML is prerendered and the Markdown is generated from that same markup at build time, so the two representations cannot drift apart.

Both ways
Negotiate on the canonical path, or add .md to it. The home page twins as /index.md; every other document appends .md to its own path.
Headers
A document carries Vary: Accept and a Link header whose rel=alternate names the other representation. An Accept header that neither type satisfies is a 406, never a silent fall back to HTML.
Not documents
Reports, shares and the audit view are the application, not public documents: noindex, no-store, and no Markdown twin. A report's Markdown comes from the API instead.

the twelve documents

canonical path · markdown twin
/→ /index.md
/sample→ /sample.md
/docs→ /docs.md
/docs/api→ /docs/api.md
/agents→ /agents.md
/terms→ /terms.md
/privacy→ /privacy.md
/about→ /about.md
/about/founder→ /about/founder.md
/about/free→ /about/free.md
/about/build→ /about/build.md
/about/contact→ /about/contact.md

Discovery

five files and one header

What an agent can learn about this service without reading a page of it. Each of these is a plain file at a stable path, served to anything that asks.

/llms.txt
What this service isWhen to use GEO.new and when not to, the allowances, the platform coverage and the standing warning that quoted report evidence is untrusted page content. Generated from the same limits the store enforces, so a figure here is the one admission applies.
/.well-known/api-catalog
Where the contract isAn RFC 9727 linkset anchored on /api/v1/, naming the OpenAPI document as service-desc and the HTML reference as service-doc. One fetch from the well-known path to the machine contract, with no HTML in between.
/openapi.json
The machine contractEvery operation, error component and header, with stable operation identities. The published package types are generated from this file, so the client and the server cannot disagree about a field.
/sitemap.xml
Every canonical documentThe HTML documents only. Markdown twins are reached by negotiation or by adding .md, and are deliberately not separate entries.
/docs/agents.md
The API guideThe public audit API written for its consumers, served as Markdown at a stable path. /docs/api is the same contract as a page.
Link header
Every document response advertises the guide (rel=describedby), the sitemap, the API catalog and the OpenAPI document (rel=service-desc), so one HEAD from any page reaches the contract.
Dead ends
A path that is no document answers 404 with a document saying so, in whichever representation was asked for, rather than 200 with an empty shell. /contact and /docs/agents are 301s to their canonical paths.

A path that looks like a website is not a dead end: geo.new/example.com audits that page, which is why an unrecognised path is classified before it is refused. The reference states which shapes are reserved; see /docs/api.

Keyless or keyed

no accounts either way
session5 audits an hourThe default. Minted by the first call, kept in your config directory, lasts seven days. Reports are private to it.
key10 audits an hourOptional. Outlives any session, keeps a usage record, has its own network bucket. Up to 5 live keys; no account and no recovery.

geo-new key create prints a key once and saves it for this machine; geo-new login <key> on another one. The same key can be made, listed and revoked in the browser at /docs/api#keys, where a browser can also claim a key so that reports made from a terminal open at their /r/ links there. Every plan still shares the ceiling everyone shares; the figures are in the reference under limits.

From a script

the same client, imported
import { createClient } from 'geo-new';

const geo = createClient({ apiKey: process.env.GEO_NEW_API_KEY });
const { audit_id } = await geo.audit('https://example.com', { fresh: true });
const { snapshot } = await geo.waitFor(audit_id, { mode: 'measured' });
console.log(snapshot.scores.catalog?.value);

The client is what the command line and the MCP server are built on. It holds a session before any create, sends an Idempotency-Key on every one, retries server and network failures twice and never retries a rate limit. It does not validate a snapshot at runtime, so an additive server change never breaks a cached copy of the package; the types come from the published OpenAPI contract.

In CI

a gate and a trend
npx -y geo-new audit https://staging.example.com --fresh --out after.json --min-score 70
npx -y geo-new compare before.json after.json --allow-missing-baseline
mv after.json before.json
Gate
--min-score fails the job (exit 6) below a floor; an unmeasured score counts as below unless --allow-unscored, so a page the audit could not read does not pass by accident.
Trend
Reports expire after seven days, so keep your own snapshots with --out and compare them offline. compare exits 7 on a drop; --allow-missing-baseline lets the first run through.
Identity
Hold a key in GEO_NEW_API_KEY. Keyed principals have a network bucket of their own, so a shared runner pool is not starved by strangers on the same address.
Reports are private, expire after seven days, and are served no-store.Never audit a URL that carries a secret in its query string.