Skip to content

Add firecrawl-research skill for the Firecrawl Research Index - #257

Open
rakshith48 wants to merge 1 commit into
K-Dense-AI:mainfrom
rakshith48:add-firecrawl-research-skill
Open

Add firecrawl-research skill for the Firecrawl Research Index#257
rakshith48 wants to merge 1 commit into
K-Dense-AI:mainfrom
rakshith48:add-firecrawl-research-skill

Conversation

@rakshith48

Copy link
Copy Markdown

Summary

Adds firecrawl-research, a skill covering Firecrawl's Research Index — a purpose-built paper index for research agents. Its distinguishing capability is question-directed passage retrieval: given a paper and a question, it returns the full-text passages that answer it, which is what lets an agent verify that a paper actually reports a method or result before citing it, instead of inferring from the abstract.

Five subcommands, all Research Index endpoints: search-papers, inspect-paper, read-paper, related-papers, search-github. Web search and URL extraction are deliberately out of scope and stay with exa-search and parallel-web.

Also raises the firecrawl-py floor in pyproject.toml from >=4.9.0 to >=4.41.0. The dependency was already declared but had no consumer; the Research Index methods are absent from 4.9.0 and 4.20.0 and only appear in later releases, so the previous floor could not satisfy this skill. Verified by installing each version and introspecting the client.

Type of change

  • New skill
  • Tests
  • Documentation

Skills touched

  • firecrawl-research

How this was tested

Every command below was run, and all five subcommands were additionally executed against the live API with a real key (not mocked).

uv run skills-ref validate skills/firecrawl-research      # Valid skill
for d in skills/*/; do uv run skills-ref validate "$d"; done   # all 164 valid
uv run --with pytest python -m pytest tests/_meta -q      # 10 passed, 1224 subtests
uv run --with pytest python -m pytest tests/firecrawl-research -q   # 34 passed
python tests/run_all.py --isolated firecrawl-research     # 1 passed, 0 failed
uv run python scan_pr_skills.py skills/firecrawl-research # LOW, 0 high/critical

tests/_meta was confirmed green on the base branch before any change, so the run above is not masking a pre-existing failure.

Live API runs (real FIRECRAWL_API_KEY unless noted, responses carried real paper ids):

Command Result
search-papers real CRISPR off-target papers with PMID/PMCID/DOI
search-papers --categories cs.LG --from-date --to-date filters applied
inspect-paper arxiv:1706.03762 canonical metadata
read-paper arxiv:1706.03762 --question ... -o file.json 3 full-text passages
related-papers ... --mode citers / --mode references poolSize/truncated reported
search-github scverse/scanpy#350 and other real hits
search-papers with FIRECRAWL_API_KEY unset keyless run succeeded, warning on stderr

Behaviour documented in the skill was derived from those runs rather than from the docs, which caught four things the docs do not state:

  • The SDK spells the date filters from_date/to_date, not the REST from/to, and takes authors/categories as lists rather than strings.
  • read-paper returns success: true with passages: [] when the index holds metadata but no full text (pmid:34515826, pmcid:PMC13172344 do this; arxiv:1706.03762 does not). The script warns on stderr and the skill documents it as "no indexed full text", not "the paper does not say this".
  • pageType and number are absent on README/repository hits from search-github, so a direct subscript raises on the first such result.
  • score is not safe to threshold on. The same search-papers query returned a ~0.98 top score and, hours later, ~0.03 with a different top paper, no query or filter change. The skill documents scores as usable only for ordering within a single response.

Reliability and keyless use

The top-level Firecrawl wrapper cannot serve the index's anonymous access: it eagerly builds a legacy v1 client and raises ValueError: No API key provided before issuing a request. The script therefore uses firecrawl.v2.FirecrawlClient, which constructs without a key. Keyless was verified end to end against the live index.

Retries are owned in one place. firecrawl-py 4.41's HTTP layer runs its own loop over transport errors and 502; left at its default that multiplies with the script's loop, so a persistent 502 would cost 4 x 3 = 12 requests with stacked sleeps. The client is built with max_retries=1, making the script the sole retry owner, and it covers 408, 429, 500, 502, 503, 504 and transport errors within one bounded budget, honouring Retry-After (delta-seconds and HTTP-date forms, capped so a pathological header cannot hang the run) and falling back to exponential backoff. Non-retryable failures exit 1 with a one-line stderr message rather than a traceback.

Both are pinned by tests that drive the real objects rather than mocks: the client tests construct an actual FirecrawlClient with and without a key, and the 502 test drives the real SDK request path with requests.get patched, asserting exactly MAX_ATTEMPTS HTTP requests. Reverting either fix fails them (3 != 1 and 12 != 4).

Related issues and references


Checklist

Skill format

  • The skill directory name and the name frontmatter match exactly.
  • The skill directory contains only SKILL.md, references/, and scripts/ — no tests/ directory and no test_*.py files.
  • SKILL.md has valid YAML frontmatter and a Markdown body.
  • Only the six spec-defined top-level fields are present; everything else lives under metadata.
  • metadata is a block mapping, not single-line JSON, and scalar values are quoted where needed.
  • Any metadata.openclaw or metadata.hermes block is a nested mapping, not a JSON string.
  • metadata.version exists, is quoted, and is bumped if an existing skill changed. (New skill, starts at "1.0"; no existing skill changed.)
  • The description says both what the skill does and when an agent should use it.

Validation and tests

  • uv run skills-ref validate ./skills/firecrawl-research passes.
  • Tests live in tests/firecrawl-research/, and the [skills.firecrawl-research] entry is in tests/skill-requirements.toml.
  • Relevant test suites pass.
  • Security scanner results are clean or explained in this PR. (See below.)

Content and safety

  • Examples and scripts were tested, or are clearly marked as illustrative.
  • No secrets, credentials, private data, or unsafe instructions are included.
  • Credentials the skill needs are named in compatibility and declared in metadata.openclaw.envVars.
  • Relevant official documentation is linked where useful.

Security scan

scan_pr_skills.py reports LOW, 0 high/critical (CI fails at HIGH). The analyzer is LLM-backed and its finding set varies slightly between runs; across runs the substantive items were:

  1. LLM_PROMPT_INJECTION — retrieved third-party text enters the agent context. Mitigated: SKILL.md carries an untrusted-data hazard section instructing the agent to quote and summarise but never follow embedded instructions. A re-scan recorded it as "explicitly and correctly mitigates this … informational residual risk only". Inherent to any retrieval skill.
  2. LLM_SUPPLY_CHAIN_ATTACK — unpinned firecrawl-py>=4.41.0. Not changed: an open lower bound matches the existing convention (exa-search uses exa-py>=1.14.0). Happy to pin if you would rather.
  3. LLM_DATA_EXFILTRATION — the documented dotenv -f .env run -- setup step loads the whole .env into the child environment. Not changed: this is the pattern exa-search already documents, and the class AGENTS.md flags as a systematic false positive for a skill that reads its own key and calls its own service. Worth changing repo-wide if you disagree, rather than in one skill.
  4. LLM_HARMFUL_CONTENT (one run only) cited templates/*.md and assets/*.md as missing. The skill references no such paths — grep finds none and tests/_meta link-checks every local link. This is the path-inference false positive AGENTS.md warns about.

Notes for reviewers

Positioning against paper-lookup. Deliberately complementary, and stated as such in this skill's routing: paper-lookup owns identifier resolution, exhaustive per-database coverage, and open-access full-text retrieval; this skill owns semantic search and passage-level verification. The documented fallback when passages are empty is paper-lookup.

-o/--output must follow the subcommand. It is declared on a shared parent parser rather than at the top level: declaring it in both places makes argparse silently reset it to None when it appears before the subcommand, which would drop the destination file without an error. A test pins both the working placement and the loud rejection of the other.

Attribution. metadata.skill-author is set to Firecrawl, following the exa-search precedent of attributing a vendor integration to the vendor. Change it if you would rather it read K-Dense Inc.

Not verified / human follow-up

  • No live API call runs in CI. The suite mocks the network, so CI needs no secret. If you want the live path exercised, add FIRECRAWL_API_KEY as a repository secret. Keyless does work — verified from a datacenter address — but the anonymous rate limit is low and shared across a runner's egress IP, so it is not a dependable CI path.
  • Retry behaviour is tested, but no real 429 was ever provoked. The 502 path runs through the real SDK request stack with the socket mocked; the 429 and Retry-After paths use a fake exception carrying the SDK's status_code/response shape, because the live rate limit was never tripped. Two SDK internals are load-bearing and worth a glance if it restructures: the error classes are not exported from the package root (so the script keys off duck-typed attributes), and firecrawl.v2.FirecrawlClient is a versioned rather than top-level import.
  • Collection version not bumped. plugin.json and pyproject.toml both remain 2.65.0 and stay in sync. Bump both together if a new skill should ship a release.
  • The firecrawl-py floor bump affects the project environment, not just this skill. Worth a uv sync on your side to confirm nothing else in the repo depended on a pre-4.41 API. Nothing else imports the package today.
  • Passage coverage and the author filter were characterised on a handful of papers, not exhaustively. The claims in the hazards section ("strong for arXiv and open-access, thin for metadata-only PubMed") are an honest generalisation from the specific ids named there, not a measured coverage figure.
  • No docs/images/firecrawl-research.png diagram. Optional per AGENTS.md, and generating one needs OPENROUTER_API_KEY, which was not available.
  • The full python tests/run_all.py --isolated sweep was not run — only the firecrawl-research entry. The sweep needs CUDA/JDK/MATLAB toolchains for other skills.

Adds a skill covering Firecrawl's Research Index: semantic paper search
over abstracts, canonical metadata lookup, question-directed retrieval of
full-text passages inside a paper, related-work expansion by co-citation
neighbourhood / citers / references, and search over GitHub issues, PRs,
discussions, and READMEs for implementation prior art. Scope stays on the
Research Index; web search and URL extraction remain with exa-search and
parallel-web.

The client is firecrawl.v2.FirecrawlClient rather than the top-level
Firecrawl wrapper, which eagerly builds a legacy v1 client and raises
ValueError("No API key provided") before issuing a request. The index
serves anonymous requests, so that would have made keyless use impossible.

The CLI owns retries outright: the SDK's internal loop is disabled
(max_retries=1) so it cannot multiply with this one, and 408, 429, 5xx,
and transport errors are retried within a single bounded budget that
honours Retry-After. Non-retryable failures exit 1 with a one-line message
instead of a traceback.

The skill documents the index's quiet-failure modes: an empty passages
array means no indexed full text rather than absence of the result, the
author/category/date filters are conjunctive over the semantic candidate
pool and silently return nothing, relevance scores are unstable enough
between calls that thresholding on an absolute value is unsafe, and
work-level deduplication needs shared DOI/PMID/PMCID rather than paperId,
which differs between a preprint and its published record.

Raises the firecrawl-py floor from >=4.9.0 to >=4.41.0. The Research Index
methods are absent from 4.9.0 and 4.20.0 and only appear in later releases,
so the previous floor cannot satisfy this skill.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant