# claude-skill.md

Monitor companies, contacts, and industries with TAMradar. Use when the user wants to monitor or track companies, people, or industries — hiring signals, job openings, job changes, funding rounds, industry mentions. Trigger phrases include: "monitor", "track", "watch", "set up alerts", "set up radar", "check findings", "get updates", "TAMradar". Examples: "monitor openai.com hires", "track Sam Altman job changes", "set up funding round alerts", "watch this company for job openings".

# TAMradar Monitoring · v1.0 · 2026-05-11

## 👤 For humans

### Option A — One-off session (simplest)

Paste this into any Claude session:

> "Go to [https://tamradar.readme.io/reference/claude-skillmd.md](https://tamradar.readme.io/reference/claude-skillmd.md) and follow the setup instructions."

Claude fetches the page and runs the flow. The `tamradar/` folder and radars it creates persist; the skill itself does not — you'll re-paste the URL next session if needed.

### Option B — Permanent install (recommended for regular use)

Run once in your project root:

```bash
mkdir -p .claude/skills/tamradar && curl -s https://tamradar.readme.io/reference/claude-skillmd.md > .claude/skills/tamradar/SKILL.md
```

After this, `/tamradar` works in any Claude Code session in that project and auto-loads when you mention monitoring or tracking. Re-run the same command any time to pull the latest version.

> **Note for readme.io viewers:** If copying this file manually, `---` YAML fences may render as `***` — replace them with `---` when saving locally.

**Full instructions:** fetch [https://tamradar.readme.io/reference/tamradar-agentmd.md](https://tamradar.readme.io/reference/tamradar-agentmd.md) for complete radar type reference, filter values, and field docs.

**Base URL:** `https://api.tamradar.com` · **Auth:** `x-api-key: $TAMRADAR_API_KEY` on every request — no Bearer prefix

## Key Rules

* **Auth:** check `$TAMRADAR_API_KEY` in env first — if unset, ask the user
* **Persistence:** save `(domain, radar_type, radar_id)` to `./tamradar/tamradar-radars.jsonl` after every 201
* **Idempotency:** check `./tamradar/tamradar-radars.jsonl` before every POST — skip if already exists
* **Singles vs bulk:** ≤10 targets → single POSTs; >10 → `POST /v1/radars/bulk` (100 per request max)
* **409 on single endpoints** — extract `radar_id` from `errors[0].reason`, store it, move on
* **409 inside bulk** — appears as `results[i].code === 409`, not HTTP 409. `retryable: false` — skip, don't retry
* **Polling response:** field is `updates[]` — not `data[]`
* **Polling cap:** max 10 `radar_id` values per call — split into multiple requests if needed
* **Filters:** omit = all; empty array `[]` = 400 error; `departments` + `seniorities` = AND across, OR within
* **Filter values:** NEVER invent — use only the exact values in the full doc or you get 400
* **Rate limits:** read `Retry-After` on 429 and wait exactly that many seconds before retrying

## Flow

```
0. BOOTSTRAP   → create tamradar/ folder + .env
1. DELIVERY    → ask webhook or local, configure accordingly
2. PRE-FLIGHT  → GET  /v1/account           (check balance — block if $0)
3. WHAT TO TRACK → ask, offer input format details + example files
4. CREATE      → POST /v1/radars/companies  (company signals)
                 POST /v1/radars/contacts   (person signals)
                 POST /v1/radars/industry   (industry-wide signals)
                 POST /v1/radars/bulk       (>10 targets, mixed types ok)
5. RETRIEVE    → GET  /v1/updates
6. MANAGE      → GET    /v1/radars/:id   (fetch one radar's config)
                 DELETE /v1/radars/:id   (only way to stop a radar — no pause endpoint)
```

## Step 0 — Bootstrap

Do this immediately — don't ask what they want to monitor yet.

**1. Check API key**

```bash
echo "${TAMRADAR_API_KEY:-(not set)}"
```

If not set: ask the user for their API key. Then ask:

> "I'll create a `tamradar/` folder to store your radars, config, and updates. Should I go ahead?"

On confirmation (or if user says just do it), create everything:

**2. Create folder structure**

```bash
mkdir -p ./tamradar/updates ./tamradar/inputs
```

**3. Write `.env`**

```bash
# tamradar/.env
TAMRADAR_API_KEY=<key_from_user_or_placeholder>
```

Also add to `.gitignore` if one exists:

```bash
echo "tamradar/.env" >> .gitignore
```

**4. Confirm setup**

Tell the user:

```
tamradar/ folder created.
  tamradar/.env              ← API key stored
  tamradar/inputs/           ← drop your target lists here
  tamradar/updates/          ← findings will land here (local mode)
  tamradar/tamradar-radars.jsonl  ← created after first radar
```

Then immediately move to Step 1.

## Step 1 — Choose delivery mode

> "How do you want to receive TAMradar updates?
>
> **A) Webhook (recommended)** — TAMradar pushes each update to your URL the moment it's found. Works with Clay, Zapier, n8n, Make, or any webhook-capable tool. You can also use [webhook.site](https://webhook.site) for a quick look at raw payloads — see note below.
>
> **B) Local files** — I'll poll every hour and save findings as JSON files in `tamradar/updates/`. No server needed."

* If **A**: ask for the webhook URL. Include it as `webhook_url` in every radar create call.
* If **B**: omit `webhook_url` from all creates. After radars are created, follow **Local polling setup**.

**webhook.site (quick testing only):**

1. **100-request cap** — free tier stops logging after 100 hits.
2. **Webhook URL is immutable** — no API endpoint exists to change it after creation. To switch destinations, DELETE the radar and recreate it. Since TAMradar charges per update delivered (not per radar), this is low-cost — you'll just replay the past couple of days of data.

Confirm the user understands both before proceeding with webhook.site.

## Step 2 — Pre-flight

```bash
curl -s "https://api.tamradar.com/v1/account" -H "x-api-key: $TAMRADAR_API_KEY"
```

```json
{
  "data": {
    "balance_remaining_usd": 42.50,
    "account": { "active_radars": 12, "total_updates_found": 3847 },
    "usage": { "month": "2026-05", "balance_used_usd": 7.50, "updates_found": 142 }
  }
}
```

`balance_remaining_usd == 0` → STOP · `< 5` → WARN and confirm · `>= 5` → proceed

## Step 3 — What to track

Ask:

> "What do you want to monitor? You can mix types:
>
> * **Companies** — hiring signals, job openings (need: domain)
> * **People** — job changes, social activity (need: LinkedIn URL + name)
> * **Industry** — funding rounds, mentions, job market trends (no target needed)"

Once they describe what they want, ask:

> "Want me to show the exact input format for each type? I can also create example files in `tamradar/inputs/` that you can fill in and hand back to me."

If yes, create the relevant example files:

**`tamradar/inputs/companies.json`** (if monitoring companies):

```json
[
  { "domain": "example.com", "radar_type": "company_job_openings", "departments": ["Engineering"], "seniorities": ["Senior", "Director"] },
  { "domain": "another.com", "radar_type": "company_job_openings" }
]
```

**`tamradar/inputs/contacts.json`** (if monitoring people):

```json
[
  { "radar_type": "contact_job_changes", "domain": "example.com", "profile_url": "https://linkedin.com/in/handle", "full_name": "First Last" }
]
```

**`tamradar/inputs/industry.json`** (if monitoring industry signals):

```json
[
  { "radar_type": "industry_funding_rounds" },
  { "radar_type": "industry_mentions", "keyword": "your keyword" }
]
```

Tell the user to fill in the files and confirm — then proceed to create radars from those files.

## Create — company

```bash
curl -s -X POST "https://api.tamradar.com/v1/radars/companies" \
  -H "x-api-key: $TAMRADAR_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "domain": "openai.com",
    "radar_type": "company_job_openings",
    "departments": ["Engineering"],
    "seniorities": ["Senior", "Director"],
    "custom_fields": { "crm_account_id": "001" }
  }'
```

Domain accepts any format (`https://www.openai.com/about` → normalized to `openai.com`). Best practice: bare domain.

## Create — contact

```bash
curl -s -X POST "https://api.tamradar.com/v1/radars/contacts" \
  -H "x-api-key: $TAMRADAR_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "radar_type": "contact_job_changes",
    "domain": "openai.com",
    "profile_url": "https://www.linkedin.com/in/samaltman",
    "full_name": "Sam Altman",
    "custom_fields": { "crm_contact_id": "003" }
  }'
```

## Create — industry

```bash
curl -s -X POST "https://api.tamradar.com/v1/radars/industry" \
  -H "x-api-key: $TAMRADAR_API_KEY" -H "Content-Type: application/json" \
  -d '{ "radar_type": "industry_funding_rounds" }'
```

## Create — bulk (>10 targets)

All radar types can be mixed in one request. `webhook_url` and `custom_fields` at the envelope level apply to all items; per-item values override.

```bash
curl -s -X POST "https://api.tamradar.com/v1/radars/bulk" \
  -H "x-api-key: $TAMRADAR_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "custom_fields": { "batch": "crm-import-2026-05" },
    "radars": [
      { "radar_type": "company_job_openings", "domain": "openai.com" },
      { "radar_type": "contact_job_changes", "domain": "stripe.com", "profile_url": "https://linkedin.com/in/patrickc", "full_name": "Patrick Collison" },
      { "radar_type": "industry_funding_rounds" }
    ]
  }'
```

**Response — 201 (all created) / 207 (partial) / 400 (all failed):**

```json
{
  "status": "partial_success",
  "code": 207,
  "timestamp": "2026-05-10T09:00:00Z",
  "custom_fields": { "batch": "crm-import-2026-05" },
  "summary": { "total": 3, "created": 2, "failed": 1, "retryable": 0 },
  "results": [
    { "index": 0, "status": "success", "code": 201, "data": { "radar_id": "c70813b3-...", "radar_type": "company_job_openings", "domain": "openai.com" } },
    { "index": 1, "status": "error",   "code": 409, "message": "Conflict: Radar already exists", "retryable": false,
      "errors": [{ "field": "domain", "reason": "A radar with this domain and type already exists. Conflicting radar_id: a4f28c91-..." }] },
    { "index": 2, "status": "success", "code": 201, "data": { "radar_id": "f9d01c55-...", "radar_type": "industry_funding_rounds" } }
  ]
}
```

**Bulk rules:**

* `status: "success"` → 201, all created
* `status: "partial_success"` → 207, some created
* `status: "error"` → 400, nothing created (all items failed validation)
* `results[i].retryable === true` → transient error (timeout / 5xx) — retry that item individually
* `results[i].retryable === false` → logic error (400/409/402) — fix input, don't retry blindly
* If `radars.length > your per-minute rate limit` → immediate **400** `bulk_exceeds_rate_limit` (not 429) — split into smaller requests or contact support

## Persist after every create

Single endpoints: after every 201, append to `./tamradar/tamradar-radars.jsonl`:

```bash
echo '{ "input_domain": "openai.com", "input_radar_type": "company_job_openings", "radar_id": "c70813b3-...", "created_at": "2026-05-01T09:05:00Z" }' \
  >> ./tamradar/tamradar-radars.jsonl
```

Bulk: iterate `results` where `status === "success"` and append each `data.radar_id` the same way.

## Local polling setup (mode B only)

Run this once, right after all radars are created. Then trigger the first poll immediately — don't wait for the schedule.

**1. Create folder structure**

```bash
mkdir -p ./tamradar/updates
```

Final layout:

```
tamradar/
  tamradar-radars.jsonl      ← radar registry (already exists)
  tamradar-poll.lock         ← polling state
  updates/
    company_job_openings.jsonl
    contact_job_changes.jsonl
    industry_funding_rounds.jsonl
    ... (one file per radar_type, created on first update)
```

**2. Write the initial lock file**

Save to `./tamradar/tamradar-poll.lock`:

```json
{ "last_discovered_at": null, "last_polled_at": null }
```

**3. Schedule recurring polls**

If using **Claude Code**:

```
/schedule every 1h — TAMradar poll (local mode): read ./tamradar/tamradar-poll.lock for last_discovered_at, fetch GET /v1/updates with since=last_discovered_at, paginate all pages, append each update to ./tamradar/updates/<radar_type>.jsonl, update lock with new last_discovered_at.
```

If using another scheduler or agent runtime: trigger the **Polling run** instructions below on your chosen interval. 1 hour recommended; 3 hours minimum.

## Polling run (executes every hour)

This is what runs on each scheduled invocation — either triggered by the schedule above or invoked manually.

**1. Read the lock**

```bash
cat ./tamradar/tamradar-poll.lock
```

Use `last_discovered_at` as the `since` parameter. If `null` (first run) → omit `since` entirely to fetch all available history.

**2. Fetch and paginate**

```bash
# First page (omit &since=... on first run)
curl -s "https://api.tamradar.com/v1/updates?since=<last_discovered_at>&limit=100" \
  -H "x-api-key: $TAMRADAR_API_KEY"
```

* If `updates[]` is empty → no new data. Skip to step 4 (update `last_polled_at` only).
* While `has_more: true` → fetch `?cursor=<next_cursor>&limit=100` and continue.
* Track the **maximum `discovered_at`** across every update seen across all pages.

**3. Write updates**

For each update, append one line to `./tamradar/updates/<radar_type>.jsonl` (create file if missing):

```json
{ "update_id": "550e8400-...", "discovered_at": "2026-05-10T09:30:00Z", "radar_id": "c70813b3-...", "radar_type": "company_job_openings", "domain": "openai.com", "content": { } }
```

**4. Update the lock**

Write back to `./tamradar/tamradar-poll.lock`:

* `last_discovered_at` → the max `discovered_at` from this run (or keep previous value if no updates)
* `last_polled_at` → current wall-clock time

```json
{ "last_discovered_at": "2026-05-10T09:30:00Z", "last_polled_at": "2026-05-10T10:00:00Z" }
```

> **Why use `discovered_at` and not wall-clock time?** The `since` parameter is API-time, not agent-time. Using `discovered_at` means if a run finds nothing, `since` doesn't advance — nothing is ever missed. If the API is temporarily down, the next run catches up cleanly.

## Poll for findings (webhook mode or manual)

```bash
# By radar ID (max 10 IDs per call — split if more)
curl -s "https://api.tamradar.com/v1/updates?radar_id=id1,id2&limit=50" \
  -H "x-api-key: $TAMRADAR_API_KEY"

# Incremental by time
curl -s "https://api.tamradar.com/v1/updates?since=2026-05-01T08:00:00Z&limit=100" \
  -H "x-api-key: $TAMRADAR_API_KEY"
```

```json
{
  "updates": [
    {
      "update_id": "550e8400-...",
      "update_type": "radar_finding",
      "discovered_at": "2026-05-01T08:30:00Z",
      "data": { "radar_id": "c70813b3-...", "radar_type": "company_job_openings", "domain": "openai.com" },
      "content": { }
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

Paginate: while `has_more: true` → fetch `?cursor={next_cursor}`. Findings retained **60 days**.

`content` shape varies by radar\_type and carries the actual signal data (job posting details, person change, funding round, etc.) — see the full docs for per-type schemas.

## Rate-limit headers

Every successful single-endpoint response includes these headers — use them to stay within budget proactively:

| Header                  | On       | Meaning                               |
| ----------------------- | -------- | ------------------------------------- |
| `X-RateLimit-Limit`     | 200, 429 | Your per-minute radar budget          |
| `X-RateLimit-Remaining` | 200, 429 | Tokens left in this window            |
| `X-RateLimit-Reset`     | 200      | Seconds until budget fully refills    |
| `Retry-After`           | 429      | Exact seconds to wait before retrying |

Bulk 429 responses also include `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.

## Error handling

| Code  | Action                                                                                                         |
| ----- | -------------------------------------------------------------------------------------------------------------- |
| `401` | STOP — ask user to verify API key                                                                              |
| `402` | STOP — tell user to add funds via their account manager or [support@tamradar.com](mailto:support@tamradar.com) |
| `409` | Single: extract `radar_id` from `errors[0].reason`, store, continue. Bulk: see `results[i]`                    |
| `400` | Show `errors[].reason` verbatim, ask user to fix                                                               |
| `429` | Wait `Retry-After` seconds (from header), then retry — max 3×                                                  |
| `5xx` | Retry once, then STOP and report `error_id`                                                                    |

## Summary (always present when done)

```
TAMradar setup complete.

Delivery mode: Local files (polling every 1h)
  Lock file:    ./tamradar/tamradar-poll.lock
  Updates dir:  ./tamradar/updates/
  Schedule:     hourly — first poll running now

Balance: $X.XX remaining

Radars active:
  company_job_openings     · openai.com  · c70813b3-...
  contact_job_changes      · Sam Altman  · a4f28c91-...  (already existed — skipped POST)
  industry_funding_rounds  · —           · f9d01c55-...

Failures: None

Registry saved to: ./tamradar/tamradar-radars.jsonl
```