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:
# 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.mdis 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 legacydocs/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:
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 frontmatterresource:;{date}= the date part oftimestamp:`.)[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):
- Read the framework name and major version from INDEX.md infrastructure table (e.g.,
WordPress 6.5→wordpress,6.x) - Bundled pack (primary — offline, always matches the running version):
If that exact file is absent, list${CLAUDE_PLUGIN_ROOT}/technologies/{framework}/{major}.x.md${CLAUDE_PLUGIN_ROOT}/technologies/{framework}/and load the best match — a{N}.x.mdfor the nearest major, elsecurrent.md,tech-pack.md, or a dated{YYYY-MM}.md. Consult${CLAUDE_PLUGIN_ROOT}/technologies/REGISTRY.mdto 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"). - GitHub (fallback — newer packs published after this install, or no bundled copy) — version-pinned raw URL:
Readhttps://raw.githubusercontent.com/neotherapper/claude-plugins/v{PLUGIN_VERSION}/plugins/beacon/technologies/{framework}/{major}.x.md{PLUGIN_VERSION}from${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json— never use themainbranch. (The bundled pack above is the version-matched source; this network path only adds packs published after the install.) - context7 MCP (if available) — ask for the framework's official API documentation
- Web search fallback — search
{framework} {major}.x API routes endpoints file structure - 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"
- 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):
- Answer the question — quote specific endpoints, field names, status codes, constraints
- Include auth requirements for any endpoint mentioned
- Cite the source file(s) — distinguish between "found in research (Phase 5)" and "from WordPress tech pack (not confirmed in this site's research)"
- 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:
- Resolve the surface file from Steps 2 / 3 (e.g.
api-surfaces/store-api.md). - Resolve the tech pack from Step 3a (e.g.
${CLAUDE_PLUGIN_ROOT}/technologies/wordpress/6.x.md). Fall back toplugins/beacon/templates/query-templates.mdwhen no bundled pack matches. - Run the renderer:
The renderer logsbash "${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"[SNIPPET-PICK:...]to stderr with the chosen snippet + the surface's auth field — useful for audit. Pass--firstto emit only the first row's script when the surface has many endpoints; default behaviour produces one script per endpoint row. - Network probe — non-skippable.
${BASE_URL}here is the surface's OKFresource:frontmatter value — the same fieldrender_query.shreads in step 3. Before running any generated script, do:
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.status=$(curl -s -o /dev/null -w '%{http_code}' --max-time 3 "${BASE_URL}") [[ "$status" == 2* ]] || echo "[OFFLINE]" - Run the script with a 30-second timeout (use
timeout 30 bash query-*.sh; fall back togtimeouton macOS hosts wheretimeoutis 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. - 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.