Everything in this file is typed into the terminal. The prompt for the agent is in 03-dung-skill-trong-agent.md.
Why use it: 105/163 skills carry a scripts/directory, and 90 of those skills have scripts written with argparse. This is a real CLI, runs deterministically, costs no tokens — usable in a Makefile, cron, CI, or just to check quickly without opening the agent.
What it produces: JSON/TSV on stdout or in a file specified by -o , plus an exit code that you must branch on.
Find a runnable script
# skill nào có scripts/
ls -d skills/*/scripts | cut -d/ -f2
# script nào là CLI argparse
grep -l argparse skills/*/scripts/*.py | head -20
every argparse script answers --help (this is the repo's CI contract)
python skills/paper-lookup/scripts/paginate.py --help
Hợp đồng "`--help` luôn chạy" không phải lời hứa suông: `tests/_contract/cli.py` sinh test case cho **mọi** script argparse trong repo, và `tests/_meta` chạy nó lên toàn bộ 163 skill trong mỗi PR.
## Ví dụ 1 — chuyển toạ độ genomic (thuần stdlib, offline, đã chạy thật)
```bash
python skills/genomic-coordinates/scripts/convert_coords.py --list
python skills/genomic-coordinates/scripts/convert_coords.py chr1 1000 2000 --from bed --to gff
Real output:
contig input output length status detail
chr1 1000-2000 1001-2000 1000 ok
And the convention table from --list:
format convention notes
bed 0-based half-open BED3/6/12, narrowPeak, broadPeak
gff 1-based inclusive GFF3
gtf 1-based inclusive GTF/GFF2, GENCODE, Ensembl
vcf 1-based inclusive POS..POS+len(REF)-1
sam 1-based inclusive SAM text POS (BAM stores it 0-based)
interval-list 1-based inclusive Picard/GATK
Scripts in the same skill: audit_intervals.py, check_contigs.py, normalize_variant.py. All four use only the standard library — nothing extra to install.
Example 2 — paginating a literature API, with count reconciliation
# xem kế hoạch gọi mà không gọi mạng
python skills/paper-lookup/scripts/paginate.py \
--api openalex --query "search=crispr" --max-records 200 --dry-run
Real output of --dry-run (exit 0, no request left the machine):
{
"api": "openalex",
"first_url": "https://api.openalex.org/works?...&per-page=100&cursor=%2A",
"delay_seconds": 0.2,
"query_format": "query is a raw parameter string, e.g. 'search=crispr' or 'filter=publication_year:2024'"
}
Supported APIs: biorxiv, crossref, europepmc, medrxiv, openalex (see --list-apis).
The sibling scripts all read from a file or - (stdin), so they can be piped together:
python skills/paper-lookup/scripts/arxiv_atom.py feed.xml --ids-only
python skills/paper-lookup/scripts/openalex_abstract.py works.json --text-only
python skills/paper-lookup/scripts/jats_to_text.py article.xml
Example 3 — sub-command client (ARAX knowledge graph)
python skills/ncats-arax/scripts/arax_client.py --help
python skills/ncats-arax/scripts/arax_client.py preflight
Sub-commands: preflight (checks OpenAPI + production version), normalize (normalizes free-text terms into CURIEs, for review only), one-hop, two-hop, summarize. No API key needed. Note the constraint the skill itself states: queries may be public, use only for non-sensitive research questions.
Exit codes — READ them, don't assume 0/1
The repo deliberately uses non-standard exit codes in places where the API returns HTTP 200 for a silent failure. Quoted from the docstring of fail() in skills/paper-lookup/scripts/_common.py:219:
Scripts here exit non-zero on silent-failure conditions — a JATS document with no
<body>, an arXiv Error entry, a pagination shortfall — precisely because the APIs return HTTP 200 for them.
| Script | Exit | Meaning | Source |
|---|---|---|---|
paper-lookup/arxiv_atom.py |
3 |
feed is arXiv error response (arrives as HTTP 200, totalResults 1, an entry named 'Error') |
arxiv_atom.py:166 |
paper-lookup/paginate.py |
4 |
shortfall when reconciling counts — returns fewer records than the API itself claims | paginate.py:478 |
paper-lookup/paginate.py |
2 |
missing --api/--query |
paginate.py:426 |
analytical-method-validation, iso-standards-readiness, pkpd-modeling (scripts/_common.py) |
0 / 1 / 2 |
EXIT_OK / EXIT_FINDINGS / EXIT_INPUT_ERROR — 1 means "there is a finding", not "crash" |
_common.py:32-34 |
exa-search, lab-hardware-cad, pyopenms |
2 |
input error | sys.exit(2) literal |
This means the automation wrapper script must branch explicitly:
python skills/paper-lookup/scripts/paginate.py --api crossref --query "query=crispr" -o out.json
rc=$?
case $rc in
0) echo "ok" ;;
4) echo "count reconciliation shortfall — kết quả KHÔNG đầy đủ, đừng dùng"; exit 1 ;;
*) echo "lỗi (exit $rc)"; exit $rc ;;
esac
With the three skills using EXIT_FINDINGS = 1, do the opposite: 1 is a valid result ("found an issue"), merging it with real errors is wrong.
How to check the exit code of any script before trusting it:
grep -rn 'sys.exit(\|SystemExit(\|EXIT_[A-Z_]* *=\|code=' skills/<name>/scripts/*.py
python skills/<name>/scripts/<script>.py --help # nhiều script ghi thẳng mã lạ vào description
Dependency
Scripts install nothing themselves. 34 skills are purely standard library — run immediately with python3 and you're done:
adaptyv, analytical-method-validation, bgpt-paper-search, clinical-decision-support,
clinical-reports, consciousness-council, dhdna-profiler, generate-image, genomic-coordinates,
ginkgo-cloud-lab, hypothesis-generation, iso-standards-readiness, markdown-mermaid-writing,
market-research-reports, ncats-arax, ontology-term-resolution, optimize-for-gpu, pacsomatic,
paper-lookup, paperzilla, parallel-web, pathml, pathogen-variant-surveillance, peer-review,
pi-agent, protocolsio-integration, research-grants, scholar-evaluation, scientific-brainstorming,
scientific-critical-thinking, scientific-writing, treatment-plans, venue-templates, what-if-oracle
(Source: the sections packages = [] in tests/skill-requirements.toml.)
For skills that need packages, tests/skill-requirements.toml is exactly the list to install — use it instead of guessing from import:
python3 - <<'PY'
import tomllib
cfg = tomllib.load(open("tests/skill-requirements.toml", "rb"))
entry = cfg["skills"]["scanpy"]
print("python:", entry.get("python", cfg["defaults"].get("python")))
print("packages:", " ".join(entry.get("packages", [])))
PY
Then run in a temporary environment, without touching the system environment:
uv run --with scanpy --with anndata python skills/scanpy/scripts/<script>.py --help
Pitfalls
- Don't merge the
scripts/of multiple skills into the samesys.path. 32 skills all ship a file namedscripts/_common.py; importing them into one process means_commonpoints to whichever skill loaded first. Run using the full path to each script, don'tsys.path.appendmultiple skill directories. - 18 packages are recorded as not installable anywhere in the section
[unavailable]oftests/skill-requirements.toml, with reasons —matlabenginerequires MATLAB preinstalled,omero-pyrequires a C++ build,flash-attn/deepspeed/bitsandbytesrequires a CUDA toolchain,rsgislib/pdalis only on conda-forge. Read that section before wasting a whole session. - A few skills need an interpreter older than 3.13 (
pytdc,molfeat,deepchem,histolab,vaex,ete3). The keypythonin the entrytests/skill-requirements.tomlof that skill states which version.