Dromad for coding agents

This page is for an agent asked something like "Investigate our visibility for AI search APIs." Dromad gives you evidence — what ChatGPT, Claude and Gemini answered, what they cited, how pages look to a crawler — and counts it. Interpreting it is your job: Dromad does not explain, recommend or score.

Every command accepts --json and prints one JSON document on stdout: the same object the API returns. Use --json whenever you will read the output programmatically.

With --json, that document is the whole output. stdout carries exactly one JSON document — the result, or the error envelope — and stderr carries nothing: no progress, no cost line, no balance. So dromad questions "<topic>" --json > out.json 2>&1 leaves a file that parses. What the progress lines say without --json is in the document (charge) and in dromad balance --json. The one exception is dromad login, which prints the sign-in URL and code on stderr because a person has to act on them. Read the exit code as well as the document: it is listed under Reading the JSON.

Check the CLI version

dromad --version

The server answers dromad 0.2.0 and newer. An older CLI is refused on every command with cli_outdated (exit code 2): nothing was run or charged, and the message gives the installed version, the required one and the upgrade command (uv tool upgrade dromad or pip install -U dromad). This matters because commands have changed meaning: before 0.2.0, dromad fanout generated questions; it now runs prompts on every engine, and dromad questions generates questions. If a command here is missing from dromad --help, the CLI is old: upgrade before doing anything else, and do not guess at an older command's meaning from this page.

Authenticate

Check first:

dromad whoami --json

It fails with not_authenticated (exit code 2) when there is no credential, and with unauthenticated (exit code 1) when the server refuses the one there is, because it was revoked or is unknown. Either way, ask the user either to run dromad login (opens a browser) or to create an API key at https://dromad.dev/account/api-keys and set DROMAD_API_KEY. Never print a key.

Check who, not only whether. When it succeeds, read email: a credential existing does not mean it is the account the user means, and the account is the one whose workspace pays. dromad login prints a code and a URL, and the token belongs to whichever account the browser session that approves the code is signed in to. The CLI cannot know that account beforehand, and a user with several browser profiles can approve from the wrong one without noticing. So:

  • If the user has named an account, sign in with dromad login --email <address>. It runs the same browser flow, and if another account approves it, it stores nothing, revokes the token that was issued and fails with account_mismatch (exit code 1), leaving any earlier credential as it was. Then ask the user to open the URL in the browser profile that is signed in to that address, and run it again.
  • After any sign-in, confirm dromad whoami --json shows the email you expect before spending anything. login also prints Logged in as <email>.
  • An API key has no such ambiguity: it is made in one account, for one workspace. On a machine with several browser profiles, prefer DROMAD_API_KEY.

Check the project

Work is filed under a project, and the directory you are in is normally linked to one:

dromad status --json

It prints the workspace, the project and the project's context (its domain, brands and competitors, which tell you what the work is about). It fails with not_linked (exit code 2) when the directory has no project. Then ask the user which project to use, or whether to start one, and run dromad link --project <pr_…> or dromad init --name "<name>" --workspace "<workspace>"; dromad list --json shows the choices. Both take flags for everything and ask nothing under --json. Do not invent a project for the user's work without asking: the workspace it is in is the one that pays. dromad unlink forgets the link.

Commands, and when to use them

Goal Command Cost
See what each engine actually searches for a prompt dromad fanout "<prompt>" --runs 3 --yes --json its prompt runs: prompts × engines × runs (--estimate prints it first)
Generate questions people might ask about a topic dromad questions "<topic>" --json $0.002 a question generated
See what the engines answer and cite for a question dromad prompt "<question>" --json $0.05 ChatGPT, $0.20 Claude, $0.07 Gemini; $0.32 on all three, the default
Count citations across many runs; check a domain's coverage dromad citations <rq_…/dr_…> --domain <d> --brand <b> --json free
Inspect one page as a crawler sees it dromad audit <url> --json $0.01
Find earlier work dromad runs list --json, dromad fanouts list --json, dromad analyses list --json free
Read one object in full dromad runs show <dr_…> --json, dromad fanouts show <fo_…> --json, dromad analyses show <fa_…/ca_…> --json free
Give the user a link dromad share <id> (and dromad unshare <id>), dromad open <id> --print free
Check the credential, and whose it is dromad whoami --json, dromad login --email <address>, dromad logout free
Check or choose the project dromad status, dromad list, dromad link, dromad init, dromad unlink free
See what each operation costs dromad pricing --json free
See what credit is left before a large batch dromad balance --json free

How the commands compose

A typical investigation:

  1. Questions. dromad questions "AI search API" --json returns questions (each with id, text, cluster_id, intent, specificity) and clusters. Choose the questions that matter for the user's goal — for visibility, the ones where an answer would name providers (discovery, comparison, pricing). These are generated, not observed: a list of prompts worth trying.
  2. Fanout (when the question is what engines search). dromad fanout "<prompt>" "<prompt>" --runs 3 --yes --json records the search queries each engine issued for each prompt, run by run. Use it to learn the vocabulary engines search with before deciding what a page should answer.
  3. Prompt runs. Run each chosen question: dromad prompt "<question>" --json. Keep the batch ID from .batch.id. To start several without waiting, use --no-wait and collect the IDs; dromad runs list --batch <rq_…> --json shows their progress.
  4. Citations. Pass all the batch IDs to one analysis: dromad citations rq_… rq_… --domain their-site.com --domain competitor.com --brand Their --brand Competitor --json. Read domain_coverage (cited runs and prompts per domain, per engine, the pages cited, and the prompts where the domain was absent or seen but not cited), domains, pages and overlap. An analysis counts answers already stored, and finished runs never change: running it again over the same runs with the same domains and brands gives the same numbers and only adds a duplicate. Before creating one, check dromad analyses list --kind citations --json and read an existing one with dromad analyses show <ca_…> --json. Create a new analysis only when the question changed (other domains or brands), the runs changed (new prompt runs, or a different subset such as one engine), or the analysis predates a change to how Dromad counts (its method; the current one is citations/v2). To learn whether anything changed in the engines themselves, run new prompts; no analysis of old runs can show it.
  5. Audits. Audit the user's pages the engines cited, the ones they skipped, and the competitor pages they cited most: dromad audit <url> --json.
  6. Report. Combine the evidence with your own reasoning and the user's repository. Link the analysis (dromad share ca_…) so the user can check the numbers.

Reading the JSON

  • Prompt: {"batch": {...}, "runs": [...]}. In each run, result.answer is the text and result.sources[] has url, domain, cited (true/false/null), citation_count and citation_positions. null means the provider does not expose it: never count it as "not cited".
  • Questions, citations: the analysis document, with results at the top level (.questions, .domain_coverage).
  • Fanout: .prompts[].engines[].runs[].queries[]. Each query has text and search_call: searches are in the provider's order, and queries with the same search_call were issued together, with no order among them. Nothing is merged across runs, so the same text under two runs is two observations and query_count counts observations; when you compare runs or engines, say how many runs a query appeared in rather than treating the union as one search. A run with no queries has searched true (the provider hid the text), false (it did not search) or null (not recorded): never read null as "did not search". Each run_id is a prompt run with the answer, sources and raw envelope.
  • Audit: dromad audit --json prints the audit result with run_id at the top (.findings[], .content, .metadata); dromad runs show <dr_…> --json prints the run with the same result under .result. Each finding has key, status (pass/fail/not_applicable, or error when the check itself failed — never read that as a pass), severity and evidence_level. Weigh suggestive and experimental findings accordingly.
  • Errors: {"error": {"code", "message", "engine", "retryable"}}. Retry only when retryable is true.
  • Exit codes: 0 done (a prompt where some engines failed is still 0, its batch partial), 1 the operation failed, 2 it could not be attempted (arguments, credentials, no project, a CLI too old, a fanout that needed --yes).

The full schema is at https://dromad.dev/api/v1/openapi.json.

Spend the user's credit with care

  • Look before you run. dromad runs list --json and dromad analyses list --json show earlier work. A finished run never changes; reuse it instead of re-asking the same question.
  • Choose engines. A prompt is priced per engine. --engines chatgpt is $0.05 where all three are $0.32, when one engine answers the question you have.
  • Choose questions. dromad questions gives 30 by default; running all of them on three engines is 30 × $0.32 = $9.60. Pick the ones that bear on the goal, say which you picked, and say what the batch will cost before you run it.
  • A fanout multiplies. It costs prompts × engines × runs prompt runs, and --runs is the multiplier: 3 is enough to see whether an engine searches the same way twice, 5 is the most allowed. Run dromad fanout … --estimate --json first and tell the user the estimated total; it also reports available_usd and whether that is sufficient. Without a terminal the command starts nothing unless you pass --yes: it fails with confirmation_required (exit code 2). The estimate is informational, not a quote: the fanout starts only if the workspace's credit covers all of it when it is created, and otherwise fails whole with insufficient_credit. One fanout queues at most 30 prompt runs (a queue limit, not a spending one): split more prompts across several fanouts.
  • Check the balance first. dromad balance --json gives available_usd. A request the credit does not cover fails whole with insufficient_credit and charges nothing; it will not succeed until the user adds credit at the URL in the message, so ask them rather than retrying.
  • Citation analyses are included. Re-slice existing runs with new --domain and --brand values rather than running new prompts.
  • A failed run costs nothing, but don't retry blindly. It records its error; check retryable first.
  • Mind the account's limits. rate_limited means the account has too many runs unfinished. Wait for runs to finish instead of retrying in a loop.

What not to claim

Dromad's numbers come from specific runs at a specific time; engines change, and the same question can be answered differently tomorrow. Report counts with their denominators ("cited in 9 of 24 runs"), say which engines and questions they come from, and keep "unknown" distinct from "no". Brand counts are naive whole-word matches. Audit findings describe one fetch of one page.