# Site Intel

> This skill should be used when the user asks questions about a site that has already been analysed with site-recon — "what endpoints does X have?", "how do I query Y?", "what did we find on Z?", "load research for...", "tell me about [site]", "what auth does X use?", "give me the API for...". If a docs/sites/{slug}/research/ folder exists for the site (or a legacy docs/research/{slug}/), use this skill rather than re-analysing. Routes to the right pre-built file without re-running the full analysis.

- Skill: `neotherapper/site-intel` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add neotherapper/site-intel`
- Raw SKILL.md: https://api.skillmd.com/api/skills/neotherapper/site-intel/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Research & Search
- License: MIT
- Author: neotherapper (https://skillmd.com/u/neotherapper)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/neotherapper/site-intel

---


# site-intel — Router Mode

Answer questions about a previously-analysed site by routing to the correct
pre-built research file. Read the file, then answer directly — do not re-analyse.

## Step 1: Find the research folder

Beacon writes to `docs/sites/{slug}/research/` as of v0.7.0. Older runs used the
legacy `docs/research/{slug}/` path (deprecated, read-only, removed in 0.8.0).
Check both — **new location first**:

```bash
# New (scoped to */research/ so reframe redesign/ folders are excluded):
find docs/sites -path '*/research/INDEX.md' 2>/dev/null | sed -E 's#docs/sites/(.*)/research/INDEX.md#\1#' | grep -i "{keyword-from-question}"
# Legacy fallback:
find docs/research -maxdepth 2 -name INDEX.md 2>/dev/null | sed -E 's#docs/research/(.*)/INDEX.md#\1#' | grep -i "{keyword-from-question}"
```

Resolution rules:
- If only the new path has the slug → use `docs/sites/{slug}/research/`.
- If only legacy has it → use `docs/research/{slug}/` and print:
  `[LEGACY-WORKSPACE] Reading deprecated docs/research/{slug}/ (removed in 0.8.0). Re-run /beacon:analyze {url} to write the new docs/sites/{slug}/research/ path.`
- If **both** exist for the slug → prefer the one whose `INDEX.md` is newest
  (`ls -t docs/sites/{slug}/research/INDEX.md docs/research/{slug}/INDEX.md | head -1`),
  use that folder, and note that the other (older) copy also exists — do **not** merge them.
  If the resolved (newest) folder is the legacy `docs/research/{slug}/`, also print the `[LEGACY-WORKSPACE]` hint from rule 2.

If no folder matches → tell the user to run `/beacon:analyze {url}` first:
```
No research found for {site}. Run /beacon:analyze {url} to analyse it first.
```

If multiple distinct slugs could match → list them (new path shown first) and ask which one:
```
Multiple researched sites found:
- docs/sites/example-com/research/ (see INDEX.md for analysis date)
- docs/research/example-api-com/ (legacy)

Which site are you asking about?
```

## Step 2: Open INDEX.md first

Always read the resolved `{research-folder}/INDEX.md` first (new `docs/sites/{site}/research/INDEX.md`, or legacy `docs/research/{site}/INDEX.md`) — it has the infrastructure summary,
quick API reference, and links to every other file. This surfaces the framework name
and version before routing.

Then check research freshness deterministically — do not compute the age yourself:

```bash
python3 "${CLAUDE_PLUGIN_ROOT}/skills/site-intel/scripts/freshness.py" "{INDEX path}"
```

- `[RESEARCH-STALE:{N}d]` → **prepend one line** to your eventual answer:
  `⚠️ This research is {N} days old (analysed {date}) and may be out of date — re-run \`/beacon:analyze {url}\` to refresh.`
  (`{url}` = INDEX frontmatter `resource:`; `{date}` = the date part of `timestamp:`.)
- `[RESEARCH-FRESH:{N}d]`, `[RESEARCH-DATE-UNKNOWN]`, or a missing/errored script → no warning; answer normally.

The warning is prepended once, before the answer; it does not repeat per file loaded and never changes routing.

## Step 3: Route to the specific file

| Question type | File to open |
|--------------|-------------|
| Tech stack, framework, hosting, CDN, bot protection | `tech-stack.md` |
| Available pages, URL patterns, site structure | `site-map.md` |
| Category IDs, taxonomy values, enums, nonces, public config | `constants.md` |
| A specific API endpoint (REST, GraphQL, AJAX) | `api-surfaces/{surface}.md` |
| Full endpoint list, OpenAPI spec | `specs/{site}.openapi.yaml` |
| How to query / test the site | `scripts/test-{site}.sh` |
| General overview, key findings | `INDEX.md` (already open) |

If the question spans multiple surfaces, open all relevant files before answering.

## Step 3a: Cross-reference the tech pack for framework-specific questions

After opening the research file, check whether the question is **framework-specific**:

**Load the tech pack when the question involves:**
- Query patterns, pagination, filtering ("how do I get all posts?", "how do I paginate?")
- Endpoint conventions specific to the framework ("what are the REST routes?")
- Authentication flows tied to the framework ("how does Laravel handle CSRF?")
- Framework-specific admin, dashboard, or config paths
- Anything phrased as "how do I" or "what's the pattern for" a specific framework feature — where the framework name or a framework-specific term (e.g., "WooCommerce", "Blade", "Eloquent") appears in the question

**Do not load the tech pack for factual questions:**
- "What endpoints did we find?" → research file is the source of truth
- "What CDN does this site use?" → tech-stack.md only
- "Show me the site map" → site-map.md only

**How to load** (same mechanism as site-recon Phase 4 — try in order):
1. Read the framework name and major version from INDEX.md infrastructure table (e.g., `WordPress 6.5` → `wordpress`, `6.x`)
2. **Bundled pack** (primary — offline, always matches the running version):
   ```
   ${CLAUDE_PLUGIN_ROOT}/technologies/{framework}/{major}.x.md
   ```
   If that exact file is absent, list `${CLAUDE_PLUGIN_ROOT}/technologies/{framework}/` and load the best match — a `{N}.x.md` for the nearest major, else `current.md`, `tech-pack.md`, or a dated `{YYYY-MM}.md`. Consult `${CLAUDE_PLUGIN_ROOT}/technologies/REGISTRY.md` to confirm the framework slug and which packs exist. If the version is missing or partial, use the nearest available major and note it (e.g., "Using WordPress 6.x pack — site is on 6.5").
3. **GitHub** (fallback — newer packs published after this install, or no bundled copy) — version-pinned raw URL:
   ```
   https://raw.githubusercontent.com/neotherapper/claude-plugins/v{PLUGIN_VERSION}/plugins/beacon/technologies/{framework}/{major}.x.md
   ```
   Read `{PLUGIN_VERSION}` from `${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json` — never use the `main` branch. (The bundled pack above is the version-matched source; this network path only adds packs published after the install.)
4. **context7 MCP** (if available) — ask for the framework's official API documentation
5. **Web search fallback** — search `{framework} {major}.x API routes endpoints file structure`
6. If no pack and no internet, proceed with research files only and note it once in the response: "No tech pack available for {framework} — answer based on research files only"
7. Use the tech pack's probe checklist and known endpoint patterns to **supplement** what the research files contain — never contradict confirmed research findings with tech pack assumptions

**Example:**
> User: "How do I query products in WooCommerce?"
>
> Load: `docs/sites/example-com/research/api-surfaces/woocommerce.md` (from Step 3)
> Also load: `${CLAUDE_PLUGIN_ROOT}/technologies/wordpress/6.x.md` (from Step 3a — framework-specific query question)
> Answer: combine what was discovered in the API surface file with the WooCommerce REST API conventions from the tech pack

## Step 4: Answer directly

After reading the relevant file(s):

1. Answer the question — quote specific endpoints, field names, status codes, constraints
2. Include auth requirements for any endpoint mentioned
3. Cite the source file(s) — distinguish between "found in research (Phase 5)" and "from WordPress tech pack (not confirmed in this site's research)"
4. Keep it concrete: "The endpoint is `GET /wp-json/wp/v2/posts?per_page=10`, returns
   a JSON array of post objects. No auth required. Found in Phase 5 via the WordPress
   tech pack probe checklist."

**When combining research + tech pack:** clearly label which facts are confirmed (from research) and which are conventional (from tech pack). Do not present tech pack conventions as confirmed discoveries.

## When research is incomplete

If the file exists but doesn't answer the question (e.g., a section says
"Phase 11 skipped — no browser available"):

```
The research file notes that [reason]. The {specific data} was not captured.
To get this, re-run /beacon:analyze {url} with a browser tool available,
or manually visit {url} and share what you see.
```

Do not guess or fabricate endpoint details. Only report what the research files contain.
If the tech pack suggests an endpoint conventionally exists but the research didn't confirm it,
say so explicitly: "The WordPress tech pack suggests `GET /wp-json/wc/v3/products` exists,
but this was not confirmed in the Phase 5 probes for this site."

## Step 5: Generate a query proof-of-life script (on demand, network-checked)

When the user asks for **real output** — phrasing like "show me what this returns",
"give me a sample", "fetch a real ...", "what does the API look like in practice",
"query it", "prove it works" — generate and (when network is reachable) run a query
script that proves the endpoint returns a few concrete records.

Factual and how-do-I questions ("what endpoints?", "how does auth work?") stay on
Step 4 and never enter Step 5.

**How to run:**

1. Resolve the surface file from Steps 2 / 3 (e.g. `api-surfaces/store-api.md`).
2. Resolve the tech pack from Step 3a (e.g. `${CLAUDE_PLUGIN_ROOT}/technologies/wordpress/6.x.md`).
   Fall back to `plugins/beacon/templates/query-templates.md` when no bundled pack matches.
3. Run the renderer:
   ```bash
   bash "${CLAUDE_PLUGIN_ROOT}/skills/site-intel/scripts/render_query.sh" \
     --surface "${research_folder}/api-surfaces/${surface}.md" \
     --site "${site_slug}" \
     --tech-pack "${CLAUDE_PLUGIN_ROOT}/technologies/${framework}/${major}.x.md" \
     --out-dir "${research_folder}/scripts"
   ```
   The renderer logs `[SNIPPET-PICK:...]` to stderr with the chosen snippet +
   the surface's auth field — useful for audit. Pass `--first` to emit only the
   first row's script when the surface has many endpoints; default behaviour
   produces one script per endpoint row.
4. **Network probe** — non-skippable. `${BASE_URL}` here is the surface's OKF
   `resource:` frontmatter value — the same field `render_query.sh` reads in step 3.
   Before running any generated script, do:
   ```bash
   status=$(curl -s -o /dev/null -w '%{http_code}' --max-time 3 "${BASE_URL}")
   [[ "$status" == 2* ]] || echo "[OFFLINE]"
   ```
   If the probe returns non-2xx / non-resolving / empty, do NOT run the script.
   Cite the script path and tell the user the surface was unreachable from this session.
5. **Run the script** with a 30-second timeout (use `timeout 30 bash query-*.sh`;
   fall back to `gtimeout` on macOS hosts where `timeout` is not in PATH). Capture
   only stdout. Truncate output at 20 lines max, 512 bytes per line. **Never echo
   $TOKEN / $COOKIE env-var values** in the answer.
6. Cite the generated script in the answer:
   ```
   Source: docs/sites/${site}/research/scripts/query-${surface}-${site_slug}-${rowidx}.sh
   Snippet picked: <First record | Authed first record> (auth: <frontmatter value>)
   Regenerate with: render_query.sh --surface ... --site ... --out-dir ...
   ```

**Important:** Step 5 does NOT decide which snippet to run — the renderer reads the
surface's YAML `auth:` field. Auth-aware snippet selection happens in `render_query.sh`,
not in user phrasing.

