# Intent

Double Agent answers two questions about every visit: **who is acting** (human, bot or AI agent) and **what they are
trying to do**, their intent. The first intent it reports is **probing**: requests that look for weaknesses, such as
`/.env`, `/.git/config`, `/phpmyadmin/`, backup files, or SQL injection in a query string.

Intent is a tag. It never changes the class, the conduct label, the recommendation or the signed token, and Double
Agent never blocks or challenges because of it. You decide what to do with it.

## What counts as probing

| Evidence | Plain words | Risk on its own |
|---|---|---|
| `path.secrets` | Asked for secret or credential files (`/.env`, `/.git/`, `/.aws/credentials`, `wp-config.php`) | low |
| `path.admin` | Asked for admin panels this site does not run (`/phpmyadmin/`, `/server-status`, `/wp-login.php` on a site that isn't WordPress) | low |
| `path.backup` | Asked for backup or database files (`*.bak`, `*.sql`, `/backup.zip`) | low |
| `path.exploit` | Asked for known exploit paths (`/cgi-bin/`, `/vendor/phpunit/`, web shells; `xmlrpc.php` off WordPress) | low |
| `path.traversal` | Tried to climb out of the site with `../` paths | high |
| `query.sqli`, `query.xss`, `query.traversal`, `query.ssrf`, `query.cmd`, `query.template` | Sent SQL, script, file-path, internal-address, shell or template injection in the address | high |
| `search.injection` | Typed injection payloads into your site search | high |
| `rate.404_sweep` | Asked for 10 or more different missing pages within 10 minutes ([edge adapter](#edge-adapter), Cloudflare) | medium |
| `catalog.scanner` | A declared security scanner from the catalog | low |

- **Risk:** `low` for one stray probe, `medium` once three different probe paths or a sweep make the pattern clear,
  `high` with an injection payload. A successful response never raises it: some adapters report `200` before the
  page renders.
- **Confidence** (0 to 0.99) grows with each piece of evidence.
- **Platform aware:** `/wp-admin`, `/wp-login.php`, `xmlrpc.php` and `/wp-content/` are normal on WordPress and
  WooCommerce sites and are never evidence there. Until the script has detected your platform, they are not counted.
- The patterns are conservative: ordinary paths and searches ("select chair", "men's shoes", a docs page about SQL)
  never match.

## Where you see it

- **Threats** (HQ › your site › Threats, on every plan): hostile requests and sessions over time, the most probed
  paths, networks and countries, class × intent, the clients behind the requests (grouped by network and user agent
  in 10-minute windows) and recent sessions.
- **Probing seen** label on the site in HQ and the site list when there was hostile activity in the last 7 days, with
  when and how much.
- **Session detail:** an Intent row with the evidence in plain words.
- **API:** `intent` on [`/v1/check`](/docs/rest), [`GET /v1/sessions/:sid`](/docs/rest#intent) and the
  [webhook](/docs/debrief).

```json
"intent": { "code": "probe", "confidence": 0.94, "risk": "medium",
            "evidence": ["path.secrets", "path.admin", "path.backup"],
            "task_kind": null, "source": "rules", "version": "intent-2026.10.1" }
```

`code` is `probe` or `unknown` (not enough evidence; the default). More intents (browsing, researching, completing a
task, scraping, credential attacks) come later; `task_kind` is reserved for them.

## Edge adapter

Most scanners never run JavaScript, so the browser script cannot see them. Report requests from your edge (a
Cloudflare Worker, or your Next.js proxy as in [Next.js › Crawlers](/docs/nextjs#crawlers)) to
[`POST /v1/hits`](/docs/rest) with your secret key. Double Agent's edge adapter:

- always reports probe paths (`/.env`, `/backup.zip`, `*.bak`), whatever the file type;
- matches the query string at the edge and sends only pattern codes (`qf`, for example `["sqli","trav"]`), never the
  query itself;
- with the Cloudflare adapter, records the real status, so 404 sweeps show. Next.js middleware runs before the page
  and reports `200`, so sweeps are not visible there, and it skips `/api` routes.

A custom sender can do the same: send `qf` with the codes your own matcher finds, and the response status.

The browser script (0.13.0 and later) checks the page's query the same way and sends codes only (`pages[].qf`).

## Privacy

Only codes and short probe paths are stored, never query strings or form values. Paths are capped at 200 characters
with emails, long digit runs and token-like segments replaced by `[redacted]`. Intent follows your plan's retention.
