Docs

CLI

The whereamimentioned command line. Check a site for AI crawlers with no account, sign in from a terminal, run scans and read reports, gate a CI build on your AI visibility score, and install the MCP server for the client you use.

Install

One line, no account, no key, no config.

Terminal
npx @whereamimentioned/cli site check-crawlers example.com

To keep it around, install it once. That puts wam on your PATH, with wamctl as an alias for machines where wam is already taken.

Terminal
npm install -g @whereamimentioned/cli
wam --help

Always use the scoped package name, @whereamimentioned/cli. The unscoped wam on npm is an unrelated package. Requires Node 20.19 or newer. This CLI sends no telemetry: it makes no request beyond the API calls that serve the command you ran, plus an update check against the npm registry that WAM_NO_UPDATE_NOTIFIER turns off.

Who it is for

The developer in CI. You have a site, a workflow and one question: did the content change we just shipped make our brand harder to find in AI answers? You want a step that prints machine-readable output and exits non-zero when a number crosses a line, and you will never open the dashboard during a build.

The founder in a terminal. You already live in a shell. You want wam scan run --wait, a progress line and a score, without a browser. You also want the site checks before you have an account at all, because that is the cheapest possible first look at the product.

Both get one binary, one credential store and one output contract: stdout is data, stderr is chatter, and --json is a stability guarantee rather than a debug convenience, so wam report get --json | jq .score works with no 2>/dev/null.

Site checks, no account

Seven commands work with no account, no key and no config, straight from a cold npx. They spend no credits.

CommandWhat it tells you
wam site check-crawlers <url>which AI crawlers your robots.txt lets in
wam site validate-llms-txt <url>score and findings for an existing llms.txt
wam site generate-llms-txt <url> [--full] [-o <file>]crawl the site and write an llms.txt
wam site generate-sitemap <url> [-o <file>]crawl the site and write a sitemap.xml
wam site validate-schema <url>validate the page's structured data
wam site check-meta <url> [--keyword <keyword>]check the page's meta description
wam site analyze-chunks <url>how the page's content chunks for retrieval

Every URL is fetched by the server, never by the CLI, so the checks see your site from the public internet and not from inside your network. generate-llms-txt and generate-sitemap write the generated file to stdout, so > llms.txt works, and put every count and notice on stderr; with -o they write the file and print a summary instead. Add --json to any of them for the full structured result. The same seven checks are the no-account tools of the MCP server.

Sign in

Terminal
wam auth login                  # browser, loopback on your own machine (default)
wam auth login --device         # SSH, containers, WSL, Codespaces
wam auth login --token          # paste a key you minted in the dashboard
wam auth status                 # what key, which organization, where it is stored
wam auth logout                 # revoke on the server, then clear locally

The default flow opens your browser at whereamimentioned.com. You pick an organization and approve, and the key comes back to the CLI over a loopback port on your own machine: a PKCE code exchange with no client secret and nothing to paste. --device is for SSH sessions, containers, WSL and Codespaces, where no browser can reach back to the machine; it prints a URL and a short code, and you enter the code in a browser anywhere. --token reads a key you already minted in the dashboard (Settings > API keys), from stdin or a prompt.

The key is stored in your operating system's credential store (Keychain, Credential Manager, or Secret Service on Linux), with a permission-checked file as the fallback where no store is available. wam auth status always says which one is in use. The CLI never prints the token.

CI never calls wam auth login. It sets WAM_TOKEN and nothing else.

Two kinds of key

An organization key reaches one organization. It is what wam auth login mints by default, it is what the dashboard mints, and it is the key to put in CI: a secret that is read by every job and every collaborator should reach exactly one organization.

An account-wide key reaches every organization you belong to, today and any you join later, and it is the only kind that can create a new one. That makes it a bigger secret, so keep it for a human's own shell: wam auth login --account-wide spells out what it reaches and asks before the browser opens. With one, you name the organization per command with --org, WAM_ORG or wam config set org.

The safety property is worth one sentence: an account-wide key gives you no more permission anywhere, only more places to use it, and in each of them you are whatever you already are. If you are a viewer in an organization, the key is a viewer there. If you are removed from an organization, the key loses it on the next request, with nothing to rotate.

API keys, the CLI and the API are included on every paid plan; the site checks need no key at all.

Scans and reports

Terminal
wam scan estimate                                  # cost and balance, spends nothing
wam scan run --wait                                # estimate, confirm, run, follow
wam scan run --wait --yes --fail-under 55 --json   # the CI form
wam report get --json | jq .score
wam scan evidence <scanId>                         # the answers behind the numbers

wam scan run always estimates first, prints the cost, asks, and only then starts the scan. --wait follows it to the end with a progress line; --fail-under exits 7 when the resulting AI visibility score is below your threshold, on scan run and on report get alike. Every command also has organization, workspace, competitor and prompt counterparts, and wam <group> --help lists them with a copy-pasteable example each.

A committed wam.json pins the organization, the workspace and the threshold for a repo, so every checkout and every CI run agree. An unknown key in it is a usage error, not a silent ignore, and it has no field for a token. It cannot set the server either: a committed file must not decide where your key is sent, so apiUrl lives in the user config (wam config set apiUrl), in WAM_API_URL or on --api-url, and is refused in wam.json.

wam.json
{
  "$schema": "https://whereamimentioned.com/schema/wam.config.json",
  "org": "acme",
  "workspace": "acme-eu",
  "failUnder": 55
}

In CI

A weekly scan that fails the job when the score drops below a line, keeps the report as an artifact, and cannot spend credits by accident.

.github/workflows/ai-visibility.yml
# .github/workflows/ai-visibility.yml
name: AI visibility

on:
  schedule:
    # Weekly, Monday 07:00 UTC. See the cost note below before making this more frequent.
    - cron: "0 7 * * 1"
  workflow_dispatch:

# Prevents two scheduled runs overlapping. The API would 409 anyway, but this is cheaper.
concurrency:
  group: ai-visibility
  cancel-in-progress: false

jobs:
  scan:
    runs-on: ubuntu-latest
    timeout-minutes: 45
    permissions:
      contents: read
    steps:
      - uses: actions/setup-node@v7
        with:
          node-version: 22

      # Fail early and cheaply if the balance cannot cover a scan. Costs nothing.
      - name: Check the balance
        env:
          WAM_TOKEN: ${{ secrets.WAM_TOKEN }}
          WAM_ORG: acme
          WAM_WORKSPACE: acme-eu
        run: npx --yes @whereamimentioned/cli@0.1 scan estimate --json

      - name: Run the scan
        id: scan
        env:
          WAM_TOKEN: ${{ secrets.WAM_TOKEN }}
          WAM_ORG: acme
          WAM_WORKSPACE: acme-eu
        run: |
          npx --yes @whereamimentioned/cli@0.1 scan run \
            --wait --yes \
            --fail-under 55 \
            --timeout 2400 \
            --json | tee scan.ndjson
          tail -n 1 scan.ndjson > scan-result.json

      - name: Fetch the full report
        if: always() && steps.scan.outcome != 'skipped'
        env:
          WAM_TOKEN: ${{ secrets.WAM_TOKEN }}
          WAM_ORG: acme
          WAM_WORKSPACE: acme-eu
        run: npx --yes @whereamimentioned/cli@0.1 report get --json -o report.json

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: ai-visibility
          path: |
            scan.ndjson
            report.json

What that workflow does on purpose:

  • WAM_TOKEN is an organization key, not an account-wide one. Nothing on the server can enforce that; it is a rule for whoever mints the secret.
  • @0.1 pins the minor. While the package is 0.x, a breaking change to the output lands in the minor, so @0 would protect nothing. Move the pins to @1 on the day 1.0.0 ships.
  • --yes is mandatory. Without it, scan run refuses in a non-interactive context and exits 2, so no workflow spends credits by accident.
  • The estimate step runs first and exits 4 when the balance is short, before anything is charged.
  • --timeout 2400 is below the job's timeout-minutes. On timeout the CLI exits 1 with the scan id and the scan keeps running server side, so the next run can still read the report.
  • --fail-under 55 is an example threshold. Put yours on the flag or in wam.json.
  • A retried step does not start a second scan. The idempotency key is derived from the organization, the workspace, the date and the CI run id, so a re-run follows the scan that already exists.

Cost rules

A scan spends real credits, and a CLI is the surface most likely to run one in a loop, so the CLI carries the most conservative rules of any surface in the product.

  • Estimate before spend, always. wam scan run asks the server for the cost first, even with --yes, and prints it before anything is charged, so it is in the CI log whether or not anyone confirmed.
  • A confirmation is a real one. The default answer is no; anything other than y or yes, including an empty line, cancels with exit 0 and no credits spent.
  • Non-interactive without --yes is a hard failure, exit 2, with nothing spent.
  • There is no flag for scan mode or repetitions, and there never will be. Every scan started from the CLI runs your plan's default; the one-off choices that cost more are made by a person in the dashboard, not by a script in a loop.
  • --fail-under never triggers a rescan. There is no --retry and no automatic re-run anywhere in the CLI. Every scan is started by exactly one explicit command.
  • Read commands are free: scan estimate, scan status, scan list, scan evidence, report get, prompt list, competitor list, org list, workspace list and every wam site command spend zero credits.
  • wam org create and wam workspace create spend nothing either, and they still confirm, because neither can be undone from the CLI.
  • When the balance is short, the CLI prints what the scan needs, what the organization has and the billing page, and exits 4. It does not retry, does not offer to buy credits, and does not suggest a smaller scan.
  • As a ceiling that does not depend on the CLI behaving, a key may start at most 3 scans per hour. The server names the cap and when it resets.

Installing the MCP server

The CLI is the installer for the whereamimentioned MCP server, because no single config snippet works everywhere: the top-level key and the transport name differ per client.

Terminal
wam mcp install --client cursor
wam mcp install --client vscode --print   # show the snippet, write nothing
wam mcp url                               # the endpoint URL for this org and workspace

--client accepts claude-code, cursor, vscode, windsurf, zed, warp, opencode, amp and jetbrains. The command merges the whereamimentioned entry into the client's existing config, preserves every other key, and writes a backup next to the file first. A project-scoped file never receives the raw token: it gets ${WAM_TOKEN} and a reminder to export it. Only --global writes the literal token, and only after you confirm. --print writes the snippet to stdout and touches nothing. wam mcp url prints the endpoint URL for the current organization and workspace, and nothing else, so it composes.

Exit codes

Every command exits with one of these, and wam --help prints the same table. Nothing above 125 is used, because the shell reserves 126, 127 and 128 and above.

CodeMeaningTypical cause
0Success
1Generic failureUnexpected server 500, unhandled condition
2Usage errorUnknown flag, missing argument, bad value, no workspace resolved, no org resolved on an account-wide key
3Auth required or expiredNo credential, a credential the server no longer accepts (revoked or expired), insufficient scope, insufficient role, tier gate
4Insufficient creditsHTTP 402 from the scan-create route
5Rate limitedHTTP 429
6Scan failedThe scan reached status "failed" while being followed
7Threshold not met--fail-under was set and the score was below it
8Scan already runningA 409 scan_already_running and --no-follow was passed
9ConflictThe server rejected the request as conflicting (409 conflict): the priced terms moved, or an Idempotency-Key was reused with different terms
10Ceiling reachedA 409 conflict at a limit that waiting does not clear: the plan's workspace cap, or the 25 organizations one account may own
11No paid organizationA 403 feature_not_available from wam org create, because the account owns no organization on a paid plan

Environment variables

CI sets WAM_TOKEN and, usually, WAM_ORG and WAM_WORKSPACE. Credential precedence is the --token flag, then WAM_TOKEN, then the credential store or file for the active profile. Prefer the variable over the flag: arguments leak into shell history and process listings.

VariableMeaning
WAM_TOKENThe API key. Highest-precedence credential source.
WAM_API_URLAPI origin override. Default https://whereamimentioned.com.
WAM_ORGOrg slug override.
WAM_WORKSPACEWorkspace slug override.
WAM_PROFILECredential and config profile name. Default: default.
WAM_CONFIG_DIROverride the user config and credential directory wholesale.
WAM_NO_UPDATE_NOTIFIERAny non-empty value disables the update check.
WAM_MCP_URLOnly read by wam mcp url and wam mcp install, for staging.
NO_COLORStandard. Presence disables colour regardless of value.
CIStandard. Presence implies --non-interactive.