# NexusCRM Connect — agent instructions (Codex & any CLI agent)

Use this to pull **read-only** data from NexusCRM (PingCAP's CRM) for the signed-in
user and turn it into tables, reports, or exports. Cross-platform (Windows, macOS,
Linux); needs only **Node.js 18+**.

This is the Codex-friendly twin of the Claude skill in `SKILL.md` — same engine
(`scripts/nexus_connect.mjs`), same behavior. Claude Code reads `SKILL.md`; Codex (and
other agents that read `AGENTS.md`) follow this file.

## The connector script

All work goes through **`scripts/nexus_connect.mjs`** (path is relative to this folder —
use the absolute path if this `AGENTS.md` isn't at your project root). It runs the full
OAuth Authorization-Code + PKCE flow (no password, no client secret, scope
`external.records.read`) and acts **as the signed-in user**. Defaults target
**production**.

## When the user wants NexusCRM data

1. **Connect** (once per ~hour):
   ```
   node scripts/nexus_connect.mjs auth
   ```
   A browser opens. If it shows a NexusCRM sign-in page, the user signs in there. If
   their **default** browser isn't where they're signed in, tell them to paste the
   printed URL into the browser where they ARE signed in — the listener keeps waiting,
   so a wrong-browser or flaky first attempt won't abort it.

2. **Query**:
   ```
   node scripts/nexus_connect.mjs query "SELECT Id, Name, Industry FROM Account ORDER BY Name LIMIT 50"
   ```
   Output is JSON on stdout: `{ status, totalSize, records }`. It paginates, connects
   automatically if there's no token, and re-connects once on a 401. Present `records`
   however the user asked (table, chart, CSV/XLSX export).

3. **When something keeps failing**, or before asking the user to debug anything:
   ```
   node scripts/nexus_connect.mjs diagnose 2>&1
   ```
   Offline, no token needed. Reports whether this copy of the tooling is intact — a component
   replaced on its own reads as "just old" to every other check and as `drifted` here — and turns
   recent failures into counts plus a concrete action per class. **Redirect stderr**: the readable
   report goes to stderr so `query` keeps stdout clean, so `diagnose > file` writes nothing. Use
   `2>&1`, or `diagnose --json` for stdout.

   **Both local paths record.** The install check applies always. The activity summary covers calls
   through BOTH this CLI (`surface: cli`, since v1.9.0 — the commands documented above) and the
   bundled MCP server (`surface: mcp`). Your calls ARE recorded and show up in `diagnose`; entries
   written before v1.9.0 carry no surface and read as `unknown`. The shipped Claude plugin
   records nothing because it declares no MCP server at all (it
   ships skills only and contains no installer — the `install.sh` that registers the local server
   comes from the separate CLI artifact, `nexuscrm-connect-cli.tgz`). On THAT path only —
   plugin installed, nothing else — `diagnose` is the install check plus an empty activity
   section, and that is expected. Your CLI calls are not in that case.

   A failed record holds the tool name, error code, duration, and the query with quoted text,
   numbers and dates replaced by `?` — identifier-shaped tokens survive by design. A successful one
   holds tool name, row count and duration; the query text is not kept, but the call is. Local only
   (`~/.nexuscrm-connect/diagnostics.jsonl`, 0600), nothing uploaded. `NEXUS_NO_DIAGNOSTICS=1`
   disables recording.

Other commands: `whoami` (identity + token status), `selftest` (offline sanity check).

## Config (flags work the same on every OS/shell)

```
--base <url>   --client <client_id>   --port <n>   --scope <scope>
```
Staging example (identical on Windows PowerShell and macOS/Linux):
```
node scripts/nexus_connect.mjs auth --base https://nexuscrm-new-staging.pingcap.com --client <staging_app_key>
```

## SOQL quick map

- My accounts → `SELECT Id, Name, Industry, Type FROM Account ORDER BY Name LIMIT 200`
- Open opps by stage → `SELECT StageName, ARR_Amount_USD__c FROM Opportunity WHERE StageName NOT IN ('Launched','Closed Lost','Closed Won')` (group in code; NOT `IsClosed = false`, which counts 197 of 214 realized `Launched` deals as open; `Amount` is DEPRECATED — never use it for deal size)
- Top deals → `SELECT Name, ARR_Amount_USD__c, StageName, Launch_Date__c, Account.Name FROM Opportunity ORDER BY ARR_Amount_USD__c DESC LIMIT 20` (deal size = Net New ARR, never Amount/ACV)
- This quarter → add `WHERE CloseDate = THIS_QUARTER` (also `THIS_MONTH`, `LAST_N_DAYS:30`)
- Contacts / leads → `SELECT Id, Name, Email, Title FROM Contact LIMIT 200` · `... FROM Lead WHERE IsConverted = false`

## Data caveats (real, observed)

- `IsWon`/`IsClosed` disagree with the stage → derive win/loss AND open/closed from `StageName` (Closed Won / Closed Lost / Launched). Prod 2026-08-04: 13 rows object-wide have `IsWon` true, none of them among the 872 `Closed Won`; `IsClosed` says not-closed on 197 of 214 `Launched`.
- Duplicate Opportunity rows exist → dedupe by `Id` when summing amounts/counts.
- Stage picklist varies (`Negotiation` vs `Negotiating`) → merge obvious variants when bucketing.

## Security

Read-only only — never request write scopes. Run **as the signed-in user**: never log
in as someone else, never type a password into the script, and never read auth tokens
out of browser storage. If sign-in fails, tell the user to sign in to NexusCRM and
retry — don't work around it.
