csml-rpi/ai-cfd-scientist/cfd-literature
Claude Code and agent skill by csml-rpi/ai-cfd-scientist
- community
Checking that the SKILL.md file is still in the repository.
Retrieve CFD literature for a topic via Semantic Scholar (with optional OpenAlex / arXiv / web supplements) and write a normalized lit.json. Use when the user wants a literature survey for a CFD study, or when cfd-pipeline / cfd-hypothesis / cfd-paper needs lit.json upstream. Self-contained — no Python helper required, but a one-shot script fast-path is documented at the bottom.
Install
npx vskill@latest install csml-rpi/ai-cfd-scientist/cfd-literatureSKILL.md
cfd-literature
Build the canonical lit.json artifact that every downstream skill (cfd-hypothesis, cfd-requirements, cfd-paper) consumes.
This skill is self-contained. The agent makes the HTTP calls itself, normalizes the response, and writes the artifact. The Python helper is only an optional one-shot.
Hard rules (slice 14)
- Semantic Scholar is mandatory.
lit.jsonmust contain at least one record sourced fromhttps://api.semanticscholar.org/graph/v1/paper/search(i.e. at least one record with"source": "semanticscholar"). The OpenAlex / arXiv / web supplements (Step 5) are additive — they do not substitute for the S2 call. Authoringlit.jsonwithout making the S2 HTTP call is forbidden. - `S2_API_KEY` MUST be used when set. Before making any S2 HTTP request, run
echo "${S2_API_KEY:+set}"(orprintenv S2_API_KEY | head -c 4). If the variable is non-empty, the request MUST include thex-api-key: $S2_API_KEYheader. Falling back to the public (unauthenticated) endpoint whileS2_API_KEYis set is a defect — it artificially trips the public rate limit even though the user provisioned a key. The only acceptable path to the unauthenticated endpoint isS2_API_KEYbeing genuinely unset/empty in the shell. If you see 429 from S2 and you have a key set, the request was misconfigured — fix the header, do not retry without it. - Provenance is recorded. Every record carries a
"source"field ("semanticscholar","openalex","arxiv", or"web"). Records without asourcefield are treated as fabricated by downstream gates. - Empty-result handling is explicit, not silent. If S2 returns zero useful records after filtering, write
lit.jsonas[]AND emitliterature_empty_resultto the timeline AND surface the empty result to the agent in the response so the user sees it. Do NOT silently advance tocfd-hypothesiswith an empty lit set — the downstream H10 paper-stage citation gate would still demand citations the agent has no source for. - `checkpoints/literature_done.json` requires `lit.json` to exist (even if
[]) AND the timeline event to be present. The orchestrator-skill stage-gate--mode preflight --target-stage hypothesischeckscheckpoints/literature_done.jsondirectly; if the agent writes the checkpoint without S2 being called, the gate cannot detect it, so a downstreamcfd-paperStage 0.5 enrichment + H10 audit acts as the final defense.
Inputs
topic(required): research topic stringout-dir(required): run directory; created if missingmax_papers(optional, default 20): respect the user's limit if they specified ones2_api_key(optional): read fromS2_API_KEYenv var if not passed
Output
<out-dir>/lit.json — JSON array of paper records:
Recipe (primary, agent-driven)
Step 1 — Build the query
Read the user's topic verbatim. Do not rephrase or "improve" it — the user's wording is the ground truth. If the topic is multi-clause (e.g. "LES of backward-facing step Re=5100 with comparison to DNS"), keep it as-is for Semantic Scholar; the API does fuzzy keyword matching.
If the user provided a specific maximum number of papers, use that exactly. Otherwise default to 20.
Step 2 — Call Semantic Scholar Graph API
Endpoint: GET https://api.semanticscholar.org/graph/v1/paper/search
Query parameters:
query= the topic string (URL-encoded)limit=min(max_papers, 100)(S2 hard caps at 100 per request; paginate withoffsetif you need more)fields=paperId,title,abstract,year,citationCount,venue,externalIds,url,authors
Authentication — read this first, do NOT skip:
Before issuing the request, check whether S2_API_KEY is set:
- If `S2_API_KEY` is non-empty: include
x-api-key: $S2_API_KEYon every request toapi.semanticscholar.org. This is mandatory (Hard rule #2). The authenticated endpoint has dramatically higher rate limits and is the path the user provisioned. Example withcurl:
``bash curl -sS -H "x-api-key: $S2_API_KEY" \ "https://api.semanticscholar.org/graph/v1/paper/search?query=<urlencoded>&limit=<n>&fields=paperId,title,abstract,year,citationCount,venue,externalIds,url,authors" ``
Example with Python requests:
``python import os, requests headers = {"x-api-key": os.environ["S2_API_KEY"]} r = requests.get( "https://api.semanticscholar.org/graph/v1/paper/search", params={"query": topic, "limit": limit, "fields": fields}, headers=headers, timeout=30, ) ``
If you call S2 without the header while the key is set, that is the defect this rule exists to prevent. Re-issue the request with the header.
- Only if `S2_API_KEY` is unset/empty: use the public endpoint (no
x-api-keyheader). It is rate-limited to ≈100 requests / 5 min — back off and retry with exponential delay on 429.
Never use the public endpoint when S2_API_KEY is set. There is no scenario where stripping the header is the correct choice while the user has a key provisioned.
Step 3 — Filter for CFD relevance
S2 search is loose; many results will be off-topic. Drop a paper when:
abstractis null AND title doesn't contain any CFD/fluid keyword (flow,turbulence,Reynolds,LES,RANS,DNS,OpenFOAM,mesh,boundary layer,viscosity, …) — only filter on title when the abstract is unavailable.year < 1980(very old; usually not what the user wants unless the topic explicitly mentions a classical reference).- The paper is a duplicate of one already kept (match on
paperId, then on lowercased title).
Don't be aggressive. When in doubt, keep the paper.
Step 4 — Sort
Primary: citationCount descending. Secondary: year descending. This biases toward foundational + recent.
Step 5 — Optional supplements
If after filtering you have fewer than max_papers / 2 results, supplement from:
- OpenAlex —
GET https://api.openalex.org/works?search=<topic>&per-page=25— same field-mapping (title, abstract, publication_year, cited_by_count, doi, authors). - arXiv —
GET http://export.arxiv.org/api/query?search_query=all:<topic>&max_results=25(Atom XML; parseentry/title,entry/summary,entry/published,entry/id).
Tag supplemented entries with "source": "openalex" or "source": "arxiv". Do not invent records.
Step 6 — Write lit.json
- Truncate to
max_papers. - Sort once more (citation desc).
- Write JSON, indent 2, UTF-8.
Step 7 — Append to timeline
Open <out-dir>/timeline.json (create as [] if missing) and append:
Skip if already done
If <out-dir>/lit.json exists and is a non-empty array, skip the search and append a literature_skipped_existing event. The user can force regeneration by deleting lit.json first.
Anti-hallucination rules
- Never invent a paper. If the API returns nothing useful, write an empty
[]and emit a timeline eventliterature_empty_resultso downstream skills can react. Do not fabricate titles, DOIs, or abstracts to "fill in" the array. - Never invent citation counts. If the field is missing in the response, leave it
null(not 0). - Never invent authors. Trust the API response shape exactly.
Optional script fast-path
If scripts/lit.py is present (it is, in this repo's LangGraph pipeline) and you would prefer to delegate the HTTP/parse work, you may run:
Same artifact contract. The Python script reads S2_API_KEY from the environment and attaches the x-api-key header automatically (scripts/lit.py:148), so the auth contract from Hard rule #2 is preserved. Make sure the variable is exported in the shell before invoking:
Use this script when running inside the conda env and the script is reachable; use the agent recipe otherwise (e.g. when running from a different agent framework or when cfd-skills/ is symlinked into a non-Python project).
Notes
- Citation enrichment for the bibliography (
cfd-paper) happens later via DBLP/CrossRef incfd-paper's citation step. This skill produces only the discovery dataset. - For multi-flow OED (
--oed-multi-flow) you may want to runcfd-literatureonce per flow with the flow-specific topic — that produces multiplelit.jsonfiles; downstream skills handle either case.
Next
After lit.json and checkpoints/literature_done.json exist on disk, your next action is to invoke the next skill in the chain. Do not stop, summarize, or wait — this is a literal handoff.
Read <out-dir>/state.json#mode, then invoke from this table:
mode | Next skill | |
|---|---|---|
research, code_mod, open_discovery | Skill cfd-skills/cfd-pipeline — run only Steps 5 (baseline_setup) and 6 (metric_setup); write baseline_metrics.json, metric_definitions.json, and the matching checkpoints/*_done.json. Its own ## Next then chains onward. |
mode == analysis_only / paper_only / mesh_gate does not pass through this skill, so no branch is needed here.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingcfd-skills/cfd-literature/SKILL.md
Popularity
- Repository stars
- 51
- Repository forks
- 6
- 7-day trend score
- 20
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/csml-rpi/ai-cfd-scientist/cfd-literature)