File DA-003 View as Markdown
CLI
The CLI installs the snippet into your project, checks a live site, and manages your sites and keys from the terminal. Use it when you want a repeatable command instead of a manual edit, or when your coding agent has no skills support.
npx @doubleagent-so/cli init
The package is @doubleagent-so/cli. Install, verify and account commands need Node 18 or later. simulate needs Node 20 or later and Chromium (see simulate).
init
init finds your stack, shows the diff and asks before writing. Run it from the website's folder (in a monorepo, the frontend package).
| Command | What it does |
|---|---|
init | Keyless install. No account, no key. |
init --key pk_live_… | Installs with your public key. Running it again on a keyless install adds the key in place. A secret key (sk_…) is refused. |
init --email you@company.com | Creates an account and a site, installs the site's public key and prints a test secret key once. |
init --yes --json | No prompt, and a JSON report. Use this from a coding agent. |
init --dry-run | Shows the diff and writes nothing. It never creates an account. |
Other flags: --profile <name> sets data-profile (default auto, see Site profiles), --domain sets the domain for the claim link and the new site, --name names the new account, --test installs the test key with --email, and --cwd <dir> runs it on another folder. $DOUBLEAGENT_KEY works like --key.
A keyless install ends with a line like this:
Installed without a key. Claim shop.example.com at https://app.doubleagent.so/claim?domain=shop.example.com to see retained data. Retention and collection limits apply.
The domain comes from --domain, the homepage in package.json, or a CNAME file. See Claim a domain for what is kept until then.
Where init puts the snippet:
| Stack | File |
|---|---|
| Next.js App Router | app/layout.* with next/script |
| Next.js Pages Router | pages/_document.* inside <Head>, created if missing |
| Vite, React, Vue (Lovable, Bolt, v0) | index.html <head> |
| Static HTML | Every root *.html, or public/index.html |
| Astro | src/layouts/*.astro, with is:inline |
| Nuxt | app.head.script in nuxt.config, or plugins/doubleagent.client.* |
| SvelteKit | src/app.html, before %sveltekit.head% |
| Remix, React Router | app/root.* <head> |
| WordPress theme | header.php, before wp_head() |
| Shopify theme | Nothing is edited. It prints the snippet to paste into layout/theme.liquid; see Shopify. |
With --json the report looks like this:
{ "stack": "next-app", "status": "install", "dry_run": false, "keyless": true, "key": null,
"domain": "shop.example.com", "claim_url": "https://app.doubleagent.so/claim?domain=shop.example.com",
"account": null, "files_changed": ["app/layout.tsx"], "integrations": ["ga4"], "next_steps": ["…"], "diff": "…" }
Exit codes: 0 done, 1 error or you said no, 2 stack not recognised (it prints the snippet to paste by hand).
verify
Checks a published page: the script tag, the queue stub and the key, then asks the API's install check whether beacons are arriving.
npx @doubleagent-so/cli verify https://shop.example.com
A keyless install passes. It ends with Installed correctly. and exit 0, or lists each problem with a fix and exits 1. Add --json for a machine-readable report.
verify-domain
Proves you own a domain and claims its data. You need to be logged in.
npx @doubleagent-so/cli verify-domain shop.example.com --method dns
The method is dns by default; meta, file and script also work (see Claim a domain). It adds the domain to your site if needed and checks it. On success it prints how many earlier sessions were claimed. If the proof is not there yet, it prints exactly what to publish and exits 1. Use --site st_… when you have more than one site.
login, sites and keys
npx @doubleagent-so/cli login
npx @doubleagent-so/cli sites
npx @doubleagent-so/cli keys create --kind sk --env live
login uses a device code: approve it at app.doubleagent.so/device. The session is saved to ~/.config/doubleagent/credentials.json (readable only by you). logout --all ends every session.
keys lists, creates, rotates or revokes keys (keys rotate <key_id>). It uses your only site unless you pass --site st_…. A new or rotated secret key is printed once. All three commands take --json.
snippet and create-account
These two power the Agent Skill. They are handy when you want the exact snippet for one platform, or an account without touching any file.
npx @doubleagent-so/cli snippet wix
npx @doubleagent-so/cli create-account --email you@company.com --domain shop.example.com
snippet <stack> prints where the code goes and the code itself. Stacks: html, vite, next-app, next-pages, astro, nuxt, sveltekit, remix, wordpress, wix, squarespace, webflow, shopify. It takes --key, --profile and --json.
create-account creates the account and its first site, solves the sign-up proof of work, and prints the keys once with the DNS record to verify the domain. It takes --domain, --name and --json.
simulate
Opens your site in a fresh Chromium and acts like a bot or an agent, so you can see what Double Agent makes of it. Install the browser once:
npx @doubleagent-so/cli simulate --install-browser
npx @doubleagent-so/cli simulate https://shop.example.com --scenario agent
| Option | What it does |
|---|---|
--scenario observe|bot|agent | observe (default) just watches. bot acts fast and repeats. agent pauses between actions. |
--pause, --duration, --delay, --scroll, --interval | Timing, in milliseconds (--duration in seconds, 2 to 120) |
--profile, --user-agent | The detector profile and the browser's User-Agent |
--headed | Shows the browser window |
--output <file>, --json | Where the report goes (default doubleagent-simulation.json), or print it |
--report | Lets the SDK already on your site send these visits to your account |
--list | Lists agent ids and profiles |
The bot and agent runs click and type on temporary test controls added to the page. They never submit your real forms. The report has the verdict from the SDK on your site (when there is one), a behaviour-only verdict and the signals collected. The scenario does not force the result.
By default nothing is sent to Double Agent. With --report, the visits land in your dashboard like real ones and are not marked as tests. Exit 0 means the run finished; 1 means a bad option, a browser error or missing evidence.
simulate --help lists every option, including the --agent-name and signing flags used with ERC-8004 below.
agents: ERC-8004 identities
Looks up an agent in the ERC-8004 identity registry on Ethereum. No wallet and no transaction are needed, only an HTTPS RPC URL.
export DOUBLEAGENT_ETHEREUM_RPC_URL=https://ethereum-rpc.publicnode.com
npx @doubleagent-so/cli agents resolve --agent-name acme.shopping-assistant --token-id 22 --json
The answer has the token's owner, its wallet, the registration URI and the block it was read at. It does not fetch the registration document.
| Command or flag | What it does |
|---|---|
agents resolve --agent-name <operator.agent> --token-id <n> | Reads the registry entry |
--chain-id, --registry | Another chain or registry (default: chain 1, the official registry) |
--reviewers <addr,…>, --tag1, --tag2, --reputation-registry | Reads reputation from up to 5 reviewers you trust |
--output <file> | Saves the snapshot as JSON |
agents resolve … --site st_… | Saves the identity to your site (needs login, Owner or Admin) |
agents list --site st_… | Lists saved identities |
agents remove <id> --site st_… | Removes one |
A registry lookup proves the agent is registered. It does not prove that a given visit came from that agent. To make a visit count, the agent has to sign its requests; Verified agents explains how. The CLI can do that in a test run: simulate --agent-name … --token-id … --report --sign-requests --sign-api https://api.doubleagent.so, with the key in DOUBLEAGENT_ETHEREUM_PRIVATE_KEY. The key stays in the CLI and never goes into the page.
Environment variables
| Variable | Used for |
|---|---|
DOUBLEAGENT_KEY | Public key for init, same as --key |
DOUBLEAGENT_API | Another API origin, same as --api |
DOUBLEAGENT_PORTAL | Another portal origin for the claim link, same as --portal |
DOUBLEAGENT_SESSION | A session token instead of login (for CI) |
DOUBLEAGENT_ETHEREUM_RPC_URL | HTTPS RPC for agents resolve and simulate --resolve-identity |
DOUBLEAGENT_ETHEREUM_PRIVATE_KEY | Signing key for simulate --sign-requests |
Next: Claim a domain to see your data, or read the Verdict a simulation returns.