---
name: claude-api-probe
description: Generate a paste-into-DevTools snippet that probes a Claude.ai internal API endpoint and downloads the response as JSON. Use when the user wants to test an unknown Claude internal endpoint, verify a response shape, or capture data for fixtures. Output is a single self-contained async IIFE the user pastes into the DevTools console on claude.ai. The downloaded filename includes the HTTP status so 200 vs 404 is visible at a glance.
disable-model-invocation: true
---

# claude-api-probe

Codifies the paste-into-DevTools pattern we use repeatedly when reverse-engineering Claude's internal API surface during Mayia development.

## When to use

- Probing a new endpoint path (e.g. `/projects/{id}/docs`, `/organizations/{id}/recent`, etc.)
- Verifying a response shape after Claude ships a UI change
- Capturing real responses to use as test fixtures in `packages/shared`
- Quick "does this endpoint exist?" checks before committing to an adapter implementation

## Inputs the user provides

- **Endpoint path** (relative, e.g. `/api/organizations/${orgId}/projects/${projectId}/docs`)
- Optional: **method** (default `GET`)
- Optional: **body** (for POST/PATCH)
- Optional: **a specific project/conversation/user UUID** to substitute

## Output

A single self-contained snippet shaped like:

```js
(async () => {
  const orgId = document.cookie.match(/lastActiveOrg=([^;]+)/)?.[1];
  if (!orgId) { console.error('no lastActiveOrg cookie'); return; }

  const path = `/api/organizations/${orgId}/<USER_PATH>`;
  const res = await fetch(path, {
    method: '<METHOD>',
    credentials: 'include',
    headers: { 'Content-Type': 'application/json' },
    // body: JSON.stringify(<BODY>),
  });
  const body = await res.text();
  console.log('status', res.status, 'bytes', body.length);

  let pretty = body;
  try { pretty = JSON.stringify(JSON.parse(body), null, 2); } catch {}

  const blob = new Blob([pretty], { type: 'application/json' });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = `claude_probe_<NAME>_${res.status}.json`;
  document.body.appendChild(a);
  a.click();
  a.remove();
  URL.revokeObjectURL(a.href);
})();
```

## Behavior rules

- **Filename always includes HTTP status** (`_200`, `_404`, etc.) so the user knows what they got without opening the file.
- **Always downloads** — even on 4xx/5xx. The body of an error response often reveals API shape (e.g. the `not_found_error` envelope Claude uses).
- **`credentials: 'include'`** is non-negotiable. Cookies (`lastActiveOrg`, session) flow because the script runs on `claude.ai`.
- **No try/catch swallowing.** Log the status and bytes count to console so the user sees what happened.
- **Prefer console.log over console.table** for raw API output — the data is rarely tabular.

## Related context

- Memory: `~/.claude/projects/-home-arctux-mayia/memory/claude_api_surface.md` for the confirmed endpoint catalog
- Phase 0 spike: `phase-0-spike/fetch_claude_*.js` for canonical examples

## Anti-patterns

- Don't generate a snippet that uses Node's `fetch` — it must be browser DevTools code with `credentials: 'include'`.
- Don't add jQuery or any library. Pure browser APIs only.
- Don't add user prompts (`prompt()`, etc.) — paste-and-run, no interaction.
- Don't auto-download multiple files in one snippet — one probe per run.
