AGENTS.md has always said that a skill shipping scripts/ puts its tests in
tests/<name>/, but nothing checked it: 54 of the 100 such skills had no suite
at all, including docx, pptx, xlsx, pdf and scanpy. All 100 now do.
tests/_meta is the guard. It runs the shared structural contract across every
skill in a single process -- safe because it parses scripts with ast and never
imports them -- and fails when a skill ships scripts/ without a suite or
without a [skills.<name>] entry in skill-requirements.toml. It needs no
scientific packages and finishes in seconds, so skill-tests.yml blocks every
pull request on it, plus the packages=[] suites.
tests/_contract holds what the per-skill suites were each reimplementing:
frontmatter conformance, the 500-line limit, no tests or bytecode under
skills/, local links resolving, scripts parsing, no eval/exec/os.system, no
standard-library shadowing, no hardcoded local paths, valid shell scripts. Also
the --help contract, which skips when a skill's packages are absent and runs
for real under --isolated, and shared behaviour for the files docx/pptx/xlsx
and five schematic-shipping skills carry byte-identical copies of, with drift
detection so they cannot diverge silently.
67 new suites, 3325 test functions. The existing suites were retrofitted: 18
no longer pin an exact skill version, so a version bump no longer breaks a
test; 11 duplicated structural methods removed; 19 wired to the --help
contract; and 5 that failed collection without their packages now skip
cleanly. run_all.py in the bare project environment goes from 6 failures to 0.
Writing the tests surfaced 19 defects in the skills, fixed here with version
bumps. The ones that changed scientific output:
- openpiv reported vorticity 0 for a rotating flow, from a sign error in
openpiv's y-up coordinate relabelling; solid-body rotation now gives 2w
exactly, on grids of either orientation
- deepchem returned solubility predictions in z-scored space while labelling
them log(mol/L), because it transformed a y-less dataset instead of
untransforming the output
- neuropixels-analysis had the Allen and IBL ISI thresholds swapped,
contradicting its own references/QUALITY_METRICS.md and inverting the two
standards' relative strictness
- scanpy's summarize() raised TypeError on every AnnData under anndata 0.13,
which reports an unnamed None key on .layers; scanpy convert was broken
- experimental-design's Latin hypercube was never reproducible: pyDOE3 draws
from its own default_rng and ignores numpy's global seed
- primekg shipped a hardcoded path naming a person, which is why
no_personal_paths is now a contract rule
The remainder is upstream API drift, each verified against the installed
package: retired symbols in bioservices 1.16, gget helpers that returned lists
where a string was written, ArviZ 1.x kwargs in pymc, a positional-only
factory in pymoo, ReduceLROnPlateau(verbose=) in torch 2.13, a removed scvelo
parameter, and PyPDF2 in scientific-slides.
Two manifest environments could not build and are pinned: gget, where an
unpinned scanpy walked back to 1.9.8 and pulled llvmlite 0.36 which does not
compile on 3.13, and pymatgen, pinned to the snapshot its own _common.py
enforces rather than loosening that check. deepchem gains torch, without which
no model class exists.
python tests/run_all.py --isolated: 101 passed, 0 failed.
Covers the Paperclip CLI from GXL: ~11M full-text papers, 217K+ FDA/PMDA/EMA
regulatory documents, 110K+ trial protocols, and 574K+ UniProt/PDB/ChEMBL
entries exposed as a read-only virtual filesystem with line-numbered text, so
answers can cite an exact sentence.
Written against the CLI rather than the docs site, which is a JS shell that
serves almost nothing to a fetcher. Every command was run against 0.7.14 and
re-verified on 0.7.15 after the CLI self-updated mid-review. SDK signatures
were read with inspect, not transcribed.
Authentication is PAPERCLIP_API_KEY from .env, with browser OAuth as the
fallback, and the reason is agent-shaped: environment variables do not survive
between tool calls, so the natural two-step form (export, then run) leaves the
key unset on the second call. Paperclip does not fail there -- it silently
falls back to stored OAuth, a different identity. Every invocation therefore
carries a self-contained prefix:
[ -f .env ] && { set -a; . ./.env; set +a; }; paperclip <command>
The guard is load-bearing. A bare `. ./.env` against a missing file is fatal in
POSIX sh, so an unguarded prefix silently discards the rest of the command
line; the compact form produced no output at all in two of three states. The
guarded form is verified with .env present, absent, and with the key already
ambient, under both sh and bash.
Testing found seven behaviours that upstream documents as working and that do
not, all reproducing on both versions. They are recorded with workarounds
rather than repeated as fact:
- `paperclip bash '...'` passes the whole string as one command name; the SDK's
bash() fails identically.
- Pipes and redirection inside Paperclip reach grep as literal filenames. Use
the local shell, which works because the CLI writes to stdout.
- /.gxl/ files are listed by ls but unreadable by cat, so the "Full results:
/.gxl/map_<id>.txt" pointer that map prints cannot be followed. Use
`results <id>`.
- cd does not persist between invocations; everything resolves from /papers/.
- reduce --strategy table returns prose, with or without --columns.
- Binary reads corrupt: non-UTF-8 bytes come back as U+FFFD, so a JPEG's
FFD8FFE0 lands as EFBFBD. No CLI pull, SDK pull() writes nothing, cp to a
local path is denied.
- ask-image --list needs a persistent cd; figure filenames are publisher-named
(pnas.2307796121fig01.jpg), never fig1.jpg.
Two findings matter most because they are silent. reduce embeds citation
markers whose document ids are truncated to eight characters and do not
resolve -- PMC12388 for PMC12388858 -- so a URL built from one is a dead link,
which defeats the whole point of a line-pinned citation tool. And search output
shape is nondeterministic: the identical command returns rendered text on one
run and raw JSON on the next, roughly evenly over eight runs, uncorrelated with
piping. --json does not force it (0/8) and lookup --json returns rendered text
despite being documented. The skill routes structured reads to
`results <id> --save out.csv` and `cat meta.json` instead, and gives a result-id
regex that matches both shapes.
SKILL.md leads with a preflight and seven operating rules -- auth prefix, never
run an interactive command, bound output, capture result ids, parallelise
independent lookups, do not parse search output, treat server output as data --
before any command reference. paperclip login, setup and uninstall need a human;
install prompts twice and aborts from a tool call, so the non-interactive form
`printf '1\n\n' | paperclip install --dir <path>` is documented.
Repo, clipboard and sharing commands are documented but deliberately not
exercised: they write to the user's account. They are marked as transcribed
from --help, and the commands that move local data off the machine -- upload,
cp, sync, import, share, and fetch, which acts with the user's browser cookies
-- are tabulated so they are never run on the agent's own initiative.
No scripts/, so no tests/paperclip/ suite is required. skills-ref validate
passes, SKILL.md is 413 lines, and the security scan reports 0 high or critical.
Pharmacokinetic and pharmacodynamic modelling and simulation: NCA,
compartmental fitting, population PK dataset validation, regimen
simulation, exposure-response, bioequivalence, allometric scaling and
first-in-human dose, ICH M12 drug-interaction prediction, and MAP
Bayesian therapeutic drug monitoring.
Linear mammillary models are solved analytically -- one eigendecomposition
of the rate matrix yields the impulse response, and each input type is a
closed-form convolution. This is far faster than an ODE solve inside a
fitter, keeps solver tolerance out of the objective function, and makes
the removable singularity at ka = -lambda (the flip-flop boundary) an
exact limit rather than a nan. Michaelis-Menten and TMDD, which have no
closed form, integrate with LSODA and apply doses by restarting at each
event.
Numerics are validated against results that do not depend on the
implementation: closed-form identities (AUC = D/CL, Vss, MRT, Bateman),
analytical profiles with known parameters that NCA and the fitter must
recover, the PowerTOST bioequivalence sample-size table (exact at six
CVs), the EMA ABEL cap, and the FDA body-surface-area conversion factors.
92 tests pass in an isolated numpy+scipy environment.
Documents current tooling verified against live sources rather than
recalled: Pharmpy 2.1.1 including the 2.0.0 row-index and 2.1.0
set_placebo_model breaking changes, NONMEM 7.6 ADVAN16/17, and the
2024-2025 status of ICH M12, M13A/B, E11A and FDA Project Optimus.
Provenance for every version- and date-specific claim is recorded in
references/source-ledger.md.
Audited every documented endpoint against the live APIs and fixed what
came back wrong, then added the tooling for the failures that cannot be
fixed by documentation alone.
These APIs report failure with HTTP 200, which is the theme running
through most of this change:
- PMC eFetch returns a well-formed article with no <body> for non-OA
content, with the reason only in an XML comment that parsers discard.
This is the common case, not an edge case: eFetch full text covers the
~3M OA Subset out of ~10M articles.
- arXiv returns totalResults 1 and a single entry titled "Error" for a
malformed parameter, and silently rewrites an unknown field prefix to
all:, so a typo degrades a targeted search into a full-text one.
- bioRxiv/medRxiv /details/ pages are 30 records, not the documented 100,
and an out-of-step cursor is accepted with a 200 -- a step-by-100 walk
skipped records 30-99 of every hundred while looking successful.
- Europe PMC puts errCode in a 200 body.
Documentation fixes:
- Corrected bioRxiv/medRxiv page size and documented the per-endpoint
messages shape, including why total (360) and count_new_papers (232)
differ and which endpoints expose no counts at all.
- Percent-encoded the arXiv date-range brackets; the previous example
made curl exit 3 (bad range specification) before sending anything.
- Documented the PMC non-OA hazard and added the PMC OA Web Service,
which answers "is full text actually available" before the fetch.
- Corrected <arxiv:doi>: it is the journal DOI and is absent for papers
that were never published. A constructed 10.48550/arXiv.{id} resolves
at doi.org but 404s in both Crossref and OpenAlex, so it is not a
portable key.
- Corrected the arXiv <id> scheme: entry ids are http:// while the links
to the same pages are https://, inconsistent within one response.
- Flagged the /publisher/ example, which returns "no articles found" for
valid prefixes, and the api.medrxiv.org host, which 500s on paths that
api.biorxiv.org serves.
- Replaced the cross-platform fetch-tool table with a curl-first section
that matches what allowed-tools actually grants.
- Removed stray tool-call markup from the end of SKILL.md.
Europe PMC (references/europepmc.md) closes a real gap: bioRxiv and
medRxiv have no keyword search of their own, and Europe PMC indexes both.
Its fullTextXML also 404s honestly where eFetch returns a bodyless 200.
scripts/ (standard library only) covers the logic that was being
re-derived per query, each exiting non-zero on a silent failure:
paginate.py (4 = unexplained shortfall), jats_to_text.py (2 = no <body>),
arxiv_atom.py (3 = error feed, 5 = throttled), openalex_abstract.py.
paginate.py redacts credentials from the provenance URLs it emits, since
OpenAlex and Crossref authenticate by query string.
tests/paper-lookup/ has 79 tests over fixtures captured from real
responses. arxiv_error.xml is reconstructed from a verified response
rather than saved from one, and says so -- arXiv penalizes repeated
malformed requests and stayed throttled.
Completes the three GitHub Community Standards items the repository was
missing: a Code of Conduct, issue templates, and a pull request template.
- CODE_OF_CONDUCT.md: Contributor Covenant 2.1, with contact@k-dense.ai as
the enforcement contact and a pointer to SECURITY.md for vulnerabilities.
- .github/ISSUE_TEMPLATE/: three issue forms (bug report, new skill request,
existing skill improvement) plus a config.yml that disables blank issues
and routes security reports to private vulnerability reporting.
- .github/PULL_REQUEST_TEMPLATE.md: mirrors the Pull Request Checklist in
CONTRIBUTING.md so contributors see the skill-format, validation, and
safety requirements before submitting.
- CONTRIBUTING.md: link the Code of Conduct.
Introduces a skill for analyzing genomic data, including features for variant calling, mutation analysis, and lineage tracking. The implementation includes several command-line interfaces for querying genomic databases and generating reports. Updates documentation to reflect the new skill and its functionalities, ensuring users can effectively utilize the new features.
New skill for bench analytical scientists in regulated labs: planning,
evaluating, and documenting validation, verification, and transfer of
analytical procedures under whichever framework governs.
Frameworks. ICH Q2(R2) and Q14 and ICH M10 are encoded directly from their
openly licensed text, read from the adopted PDFs rather than from secondary
summaries. USP <1220>/<1225>/<1226>, the CLSI EP series, and ISO/IEC 17025 are
paywalled, so they are cited by designation and scope only and never
reproduced or reconstructed; edition numbers taken from listings rather than
the documents are marked for confirmation.
Q2(R2) content covers the restructured characteristics (range as the parent of
response and lower range limits), Table 1 tests by measured attribute, Table 2
reportable ranges, the recommended-data minima, and the 30 Nov 2023 error
correction. M10's chromatographic and ligand-binding-assay criteria are kept
strictly separate, including the LBA-only total-error limit and the differing
ISR tolerances.
Scripts. Six standard-library CLIs, no numpy and no network, computing the
statistics that decide fitness for purpose rather than the ones that look
reassuring:
- plan_validation.py framework selection and a protocol whose
acceptance criteria must be pre-stated
- check_response.py lack-of-fit F against pure error, residual runs
test, back-calculated error per level, and a
heteroscedasticity check for weighting
- check_accuracy_precision.py recovery with confidence intervals, and
precision decomposed per level into repeatability
and intermediate precision
- check_detection_limits.py DL/QL by every approach Q2(R2) allows, compared
against the reporting threshold
- check_bioanalytical_run.py M10 run acceptance including the per-level QC rule
- compare_methods.py Deming and Passing-Bablok regression plus TOST
equivalence against a pre-stated margin
Distributions are built from the regularised incomplete beta and gamma
functions and checked against published quantiles.
Scope. The skill reports and computes. It does not decide that a procedure is
validated, accept or reject a run, close an investigation, or replace the
analyst, technical reviewer, quality unit, or regulator.
Also adds 111 tests in tests/analytical-method-validation, a docs/skills.md
entry, examples.md Example 36b, and updates the README skill count to 156.
Query live pathogen genomic surveillance through the GenSpectrum LAPIS
API: which viral lineages are circulating now, how fast they are
growing, and what mutations they carry. Covers 15 instances spanning
SARS-CoV-2, influenza A (including H5N1 and the seasonal H3N2/H1N1pdm
clades), and the Pathoplexus organisms.
This is a class of question large models answer confidently and wrongly.
Lineage names post-date training; the nomenclature is a live data
structure rather than a convention (XFG only resolves through
alias_key.json); and 294 of the ~6,230 designated names have been
withdrawn or redesignated, so remembered facts are not merely stale.
Four standard-library CLIs, no API key:
resolve_lineage.py is this name still valid, what does it expand
to, what is it descended from
lineage_prevalence.py discover the top lineages in a window, then
weekly prevalence with Wilson intervals,
coverage flags, and a guarded growth fit
mutation_profile.py defining mutations, or a diff between two
lineages, for assay-match questions
reporting_lag.py measure how long sequences take to arrive and
derive a trust cutoff
Nothing hardcodes a field name. Schemas differ materially between
instances -- dateFrom is correct on SARS-CoV-2 and a hard 400 on H5N1 --
so every script reads /sample/databaseConfig and picks the collection,
submission, and lineage columns from what the instance declares.
The API traps documented in references/lapis-api.md were all verified
against the live services. The sharpest: a trailing '*' expands to
descendants only where the column carries a lineage index. pangoLineage=
XFG returns 4 and XFG* returns 640; on H5N1, clade=2.3.4.4b returns
62413 and clade=2.3.4.4b* returns 0. Silently wrong in both directions,
so lineage_filter() refuses to build the query that lies.
Two statistical guards, both prompted by wrong output during testing.
A lineage observed zero times in every week produced a confident
+0.105/week slope from the continuity correction alone as the
denominator shrank; growth fits now require real observations. And the
quasi-binomial dispersion is floored at 1, since an estimate below the
model's own scale reports an interval narrower than binomial sampling
allows.
117 tests, including live checks gated behind LAPIS_LIVE_TESTS=1 that
document the API behaviour the scripts were built against.
An unanchored "scripts/" matches at any depth, including
skills/<name>/scripts/, so every new skill's bundled tooling was
silently untrackable. Existing skills were unaffected only because
their files were already tracked.
The entry sits under "Local agent tooling" alongside .claude/ and
.agents/, so root-only was the intent.
Fold the ISO 13485 skill into an umbrella standards-readiness skill so a
single skill covers several standards instead of one skill per standard
competing for selection on every compliance-adjacent prompt.
SKILL.md becomes a router: boundary, ISO/IEC copyright rules, current
baseline, assurance-lane discipline, the shared workflow, and the CLI
contract. Per-standard depth moves into references/.
Covers four standards in this version:
- ISO 13485 medical device QMS (certification lane)
- ISO 14971 device risk management (no lane of its own)
- ISO/IEC 17025 testing and calibration laboratories (accreditation)
- ISO 15189 medical laboratories (accreditation)
_catalog.py becomes a StandardProfile registry. Each profile carries its
own process domains, scope-activity vocabulary, and scope-item fields.
validate_scope_intake, validate_evidence_manifest, and gap_analyzer take
--standard; argparse choices refuse an unlisted value with exit 2 rather
than defaulting. audit_document_records, check_capa, and
check_supplier_controls were already standard-agnostic; check_traceability
and check_qmsr_transition stay device-specific.
New references/assurance-lanes.md exists because lane confusion, not
missing documents, causes most substantive errors in this work:
laboratories are accredited and not certified, ISO 15189 accreditation
does not satisfy CLIA, and ISO 14971 has no certificate at all.
The source ledger adds entries for ISO/IEC 17025, ISO 15189, ISO/TR
24971, the GLOBAC transition, ILAC P10/G8, and the CMS CLIA lane. ISO
catalogue metadata gathered on 2026-07-26 is marked [confirm on iso.org],
since iso.org refused automated access and those entries came from
secondary summaries.
Also adds laboratory and medical-laboratory scope-intake templates, both
fail-closed, and updates docs/skills.md and docs/examples.md so the
catalog links do not 404.
Verified: skills-ref validate passes for this skill and all others; 20
tests and 23 subtests pass directly and under run_all.py --isolated;
security scan clean (1 LOW, no HIGH+). The LOW finding is a pre-existing
unreachable assert in _common.py, verified rather than "fixed".
Link the 14 K-Dense blog posts most relevant to users of these skills,
grouped into getting started, skill benchmarks and deep dives, security
and safe deployment, and complementary open-source projects. Benchmark
entries cross-link to the corresponding skill directory.
Refresh every reference against https://pi.dev/docs/latest and the four
ecosystem package pages, cross-checked with the published npm READMEs.
New reference pages (docs added them; the site nav does not surface them):
- environment-variables.md: PI_* process config, the PI_CODING_AGENT child
marker, and the session variables injected into the bash tool. The old
env-var list lived in usage.md, which no longer has that section.
- llama-cpp.md: llama.cpp router setup, /login llama.cpp, /llama.
Notable upstream drift now reflected:
- SDK: ModelRuntime.create() replaces AuthStorage + ModelRegistry;
createAgentSessionServices/FromServices runtime factory; resolveCliModel
and resolveModelScopeWithDiagnostics.
- Providers: full 30+ API-key table with env vars and auth.json keys;
xAI/OpenRouter/Radius subscription logins; provider-scoped env blocks in
credentials; models-store.json; Bedrock proxy variables.
- New thinking level "max" across settings, CLI, RPC, thinkingLevelMap, and
the themes' thinkingMax token.
- New commands: /trust, /import, /llama; pi update --all/--models/--self;
pi config; .pi/SYSTEM.md and APPEND_SYSTEM.md; trust.json.
- RPC: get_entries (with since cursor), get_tree,
get_available_thinking_levels, agent_settled, bash_execution_update,
summarization_retry_*, and the extension UI sub-protocol.
- Extensions: expanded from a summary to the real API surface, including
session-replacement semantics and footguns, withFileMutationQueue,
terminate, prepareArguments, and dynamic tool loading.
- Session format: retainedTail checkpoints and buildContextEntries().
- Packages: pi-web-access gained source_check and nine search providers and
dropped code_search, which the old reference still documented;
pi-mcp-adapter gained six config locations, lazy-keep-alive, the output
guard, and MCP_STATUS_EVENT; pi-subagents gained the watchdog, profiles,
modelScope, per-agent memory, the fleet inspector, and RPC v1.
Also fixes escape sequences that had been corrupted in earlier versions:
the Git Bash path in windows.md, the shellCommandPrefix JSON in
shell-aliases.md, and the CSI-u sequences in tmux.md and terminal-setup.md.
Bumps metadata.version to 1.2.
The skill called /api/v1/chat/completions with modalities: ["image","text"],
which reaches only 11 models. Both FLUX models the skill documented as options
are not among them, so those paths returned 404 "No endpoints found that
support the requested output modalities". Move to POST /api/v1/images, which
serves the full 38-model image catalogue.
- Parse data[].b64_json and media_type instead of
choices[].message.images[].image_url.url; output extension now follows the
returned media type, so vector models write .svg correctly.
- Send reference images as input_references; -i is repeatable for compositing.
- Add --n, --aspect-ratio, --resolution, --size, --quality, --output-format,
--background, --output-compression, --seed, --timeout, --list-models.
- Omit unset parameters. Models reject unsupported parameters rather than
ignoring them, so a fixed parameter set breaks most of the catalogue.
- Fix API key resolution: check_env_file() only read .env files, so the
documented `export OPENROUTER_API_KEY=...` never worked. Order is now
--api-key, environment, .env.
- Default to google/gemini-3.1-flash-image (GA) rather than the preview slug.
- Drop the requests dependency for stdlib urllib.
Add references/models.md with per-model parameter support, reference-image
limits, and n caps. Add tests/generate-image/ with 27 network-free tests.
Verified against the live API: default model at 16:9, flux.2-pro with --seed
and --output-format, and an -i edit all produce correct images; --list-models
returns 38 models without a key.
Covers the conventions that produce silent off-by-one and wrong-assembly
errors: 0-based half-open vs 1-based inclusive across BED/GFF/VCF/SAM and
friends, VCF indel anchoring and left-alignment, GRCh37 vs hg19 vs GRCh38
vs T2T, and genomic-to-transcript-to-CDS-to-protein positions.
Four standard-library scripts, no network:
- convert_coords.py intervals between 21 conventions
- normalize_variant.py trim and left-align against a reference, compare
two representations for equivalence
- check_contigs.py identify the assembly, report why two files
will not join
- audit_intervals.py scan a BED/GTF/GFF3/VCF for convention violations
Build signatures are read from the UCSC chrom.sizes files and the NCBI
GRCh37.p13 assembly report; region-string semantics follow the samtools
manual, including that REF:START runs to the end of the contig and that
GRCh38 HLA contig names need htslib brace quoting.
Metrology skill covering units and measurement uncertainty, with six
standard-library-first CLIs that run offline:
- propagate_uncertainty.py: GUM framework and Monte Carlo on the same
model, with the JCGM 101 clause 8 linearization check
- uncertainty_budget.py: components stated the way certificates state
them, Welch-Satterthwaite effective dof, coverage factor from t
- format_result.py: round the uncertainty first, then the value to the
same decimal place; plus-minus, concise, and ASCII forms
- convert_units.py: pint conversion including context-only relations,
with the uncertainty carried through the local derivative
- audit_units.py: static scan for silent unit and uncertainty defects
(UNIT001-004, UNC001-004, CONST001) with suppression directives
- check_plausibility.py: 14 dimensionless groups, 8 characteristic
scales, and 22 cited magnitude bands, each dimensionality-checked
before any number is reported
Measurement models are parsed to an AST and reduced by an explicit walk;
nothing is compiled or executed. Physical constants come from
scipy.constants at run time rather than from literals.
Tests in tests/uncertainty-and-units/ (85 cases) verify the metrology
against published values and assert every bundled script passes the
skill's own auditor with no findings.
Resolve free-text scientific labels to ontology term IDs and validate
existing CURIEs against the EBI Ontology Lookup Service (OLS4). Covers the
concepts whose identifiers are routinely invented rather than looked up:
tissue, cell type, disease, phenotype, assay, chemical, organism, sex, and
developmental stage.
Two stdlib-only scripts, one per direction:
resolve_terms.py text -> ID, escalating exact -> token -> fulltext and
labelling every hit exact_label / exact_synonym /
partial, so a fuzzy guess cannot pass as a match
validate_terms.py ID -> verdict (not_found, obsolete + replacement,
label_mismatch, wrong_ontology, wrong_branch), exiting
non-zero so it works as a CI gate on a metadata file
Behaviour verified against the live service, and the reason the skill ships
scripts rather than a recipe:
- exact=true is exact *token* matching, not exact label: "liver" returns 161
hits in UBERON, 1 once queryFields is restricted to label
- /search never returns is_obsolete or term_replaced_by, even when they are
named in fieldList, so only term detail can answer whether an ID is current
- ontology=efo returns MONDO and CL hits, because ontologies import each other
- the obo_id index has holes: MONDO:0000001 is live and defined by MONDO but
unindexed, so an IRI fallback is needed to avoid a false not_found
- IRIs are not all OBO PURLs; EFO and Orphanet use their own namespaces
- OxO is retired and serves HTML with HTTP 200
- a branch check does not exclude cell types from anatomy, since CARO places
cell under anatomical structure
Tests: 59 in tests/ontology-term-resolution, 53 offline with stubbed network
plus 6 live smoke tests gated behind OLS_LIVE_TESTS=1 that pin the API
behaviour above.
- Updated AGENTS.md and CONTRIBUTING.md to clarify the use of isolated environments for each skill, addressing dependency conflicts and ensuring proper testing setups.
- Modified tests/run_all.py to implement the `--isolated` flag, allowing for the creation of throwaway environments per skill based on `tests/skill-requirements.toml`.
- Improved handling of unavailable packages and added detailed instructions for contributors on managing skill dependencies.
- Updated AGENTS.md to clarify the use of the Cisco AI Defense Skill Scanner for security scanning of new or changed skills, including details on rule IDs and CLI usage.
- Adjusted pyproject.toml to pin the cisco-ai-skill-scanner dependency to version 2.0.12, ensuring the latest features and fixes are utilized.
* add OpenPIV skill under skills/openpiv
* Fix spec violations and unverified APIs in the OpenPIV skill
Verified everything against openpiv 0.25.4 in a clean venv; all 14 SKILL.md
snippets and both reference snippets now execute, and runner.py/run_example.py
run end to end on OpenPIV's bundled test1 pair.
Spec adherence:
- metadata was a JSON flow mapping, which strictyaml rejects outright -- the
skill failed `skills-ref validate` and would not have registered at all.
Converted to a block mapping.
- compatibility claimed Python 3.8+; openpiv 0.25.4 requires >=3.10.
- Added allowed-tools and a version-pinned install line.
APIs that do not exist and now do:
- `openpiv.masking` -> `openpiv.preprocess.dynamic_masking`, which returns
(image, mask). method="shirai" is not a method; it is "edges" or "intensity".
The masked image is returned already zeroed, so multiplying the frame by the
mask is wrong -- for "edges" the mask is uint8 0/255 and rescales by 255.
- `pyprocess.iterative_warping_piv` -> `openpiv.windef.simple_multipass`.
- `openpiv.smooth.smooth` -> `openpiv.smoothn.smoothn`.
- `global_val(u, v, u_threshold=, v_threshold=)` -> positional (min, max) tuples
as u_thresholds/v_thresholds.
- `local_median_val(u, v)` -> u_threshold and v_threshold are required.
- `replace_outliers(method="disc")` -> "disk"; an unknown method is not
rejected, it silently yields an all-zero kernel.
- Combining flags with np.maximum -> boolean OR; validators return bool arrays
where True marks a spurious vector.
references/advanced_algorithms.md described algorithms that do not exist in
OpenPIV ("epi-div_div", "pritzmd_piv", EDD, PrTrZMD) alongside invented
throughput and memory figures. Replaced with the real correlation, subpixel,
s2n, multi-pass, 3D, and phase-separation APIs plus the full PIVSettings table.
Two units traps found while testing and now documented:
- windef ignores settings.dt and settings.scaling_factor -- first_pass calls
extended_search_area_piv without dt, so the chain returns px/frame.
- global_val/local_median_val thresholds are in the units of u and v. After
extended_search_area_piv(dt=0.02) that is px/s, so the conventional (-30, 30)
px/frame limit rejects the entire field.
Scripts:
- runner.py: dropped --algorithm and --threads, which were accepted and never
used (--algorithm even offered a nonexistent "synthetic_aperture"), and
--mask static, which nothing implemented. --mask dynamic silently did nothing
because it caught the ImportError from the nonexistent module. Selects
correlation_method="linear" when search_area > window_size, since the default
"circular" aliases via FFT wrap-around. Validates argument ranges, pins the
Agg backend before pyplot, and no longer NaNs out the vectors it just
interpolated -- that is now opt-in via --drop_invalid.
- analyze.py: class was named PypivAnalyzer and documented as "using pivpy"
while importing neither. Renamed to PIVAnalyzer, added compute_strain and
compute_statistics to match what SKILL.md advertises, and derived the physical
grid spacing from the saved coordinates so the gradients are per unit length.
- run_example.py: was a subprocess wrapper around a hardcoded relative path.
Rewritten as a self-contained smoke test on OpenPIV's bundled image pair.
Security scan: SAFE, 0 findings.
---------
Co-authored-by: Timothy Kassis <timothy.kassis@k-dense.ai>
- Enhanced AGENTS.md to clarify skill scope and directory structure, providing clearer guidelines for skill creation and updates.
- Updated CONTRIBUTING.md to emphasize the separation of tests from skill directories, ensuring better organization and clarity for contributors.
- Revised .gitignore to include .pytest_cache, improving project cleanliness.
- Adjusted pyproject.toml to configure pytest for better test path management.
- Incremented version number in SKILL.md for autoskill to reflect recent updates.
- Introduced a comprehensive test suite for the autoskill project, including tests for backends, CLI commands, and various skill functionalities.
- Added smoke tests for LM Studio integration to validate real-time interactions.
- Implemented tests for session clustering and event fetching to ensure accurate data handling.
- Established a framework for skill description loading and matching, enhancing the robustness of skill management.
- Included redaction tests to verify sensitive information is properly handled in outputs.
- Created end-to-end tests to simulate the full autoskill pipeline, ensuring all components work together seamlessly.
- Revised the metadata format in multiple SKILL.md files to use block mapping instead of single-line JSON, enhancing YAML compatibility.
- Added a new entry for local agent tooling in .gitignore to exclude the .claude directory, improving project cleanliness.
- Removed outdated entries for AGENTS.md and CLAUDE.md from .gitignore, streamlining ignored files.
- Generated a new security scan report with detailed findings, including 888 total findings and 33 critical issues.
- Revised the `soffice.py` scripts across multiple skills to implement a secure environment variable forwarding mechanism, minimizing the risk of exposing sensitive information to subprocesses.
- Enhanced documentation in `SKILL.md` and related files to clarify the implications of using `trust_remote_code=True` and the importance of user consent when executing code from external repositories.
- Improved the command submission process in `run_pacsomatic.py` to ensure safer execution of scripts across different executors.
- Clarified the security scan report generation process in README.md, emphasizing the publication of results.
- Revised `scan_skills.py` documentation to reflect changes in report generation and the removal of the validate_report.py script.
- Updated SECURITY.md to specify the scope of vulnerabilities and improved clarity on the report's purpose and limitations.
- Adjusted the security scan workflow to remove the validation step, streamlining the process while ensuring accurate reporting.
- Updated the skill description to include support for Word templates (.dotx) alongside .docx files, broadening the skill's applicability.
- Improved the comment script to accept both unpacked directories and .docx/.dotx files directly, streamlining the user experience.
- Added automatic comment ID assignment and XML escaping for comment text, enhancing robustness and usability.
- Removed the obsolete pack.py and unpack.py scripts, consolidating functionality into existing scripts for better maintainability.
- Enhanced validation and error handling in the validate.py script, ensuring better feedback for users.
- Added guidance on treating metadata as untrusted in SKILL.md, emphasizing safe command construction.
- Updated extract_metadata.py to sanitize the year field, ensuring only digits are retained for filenames and shell arguments.
- Introduced a build_subprocess_env function in multiple scripts to securely forward necessary environment variables to subprocesses, minimizing exposure of unrelated secrets.
- Improved documentation on where credentials are sent in SKILL.md, clarifying the purpose of each environment variable used.
Scans were sequential at ~29s per skill: 72 minutes for 150 skills against a
120-minute workflow timeout. Each scan is blocked on LLM network I/O rather
than local CPU, so the work parallelizes.
- Run skills through a thread pool (SKILL_SCAN_WORKERS, default 8), building
one scanner per worker thread rather than sharing one, since the analyzers
carry mutable per-scan state. Rate-limit retry with backoff already exists
inside cisco-ai-skill-scanner, so concurrency is bounded, not retried here.
- Reuse findings for skills whose package contents are unchanged, keyed on a
SHA-256 over file paths and bytes. Invalidate on scanner version change,
model change, --full, or a 30-day backstop from the last full scan.
- Record per-skill content_hash and last_scanned in the JSON report, and
disclose carried-forward findings in the markdown header, so a reused
finding always shows when it was actually produced.
- Sort report entries by skill name so worker completion order does not churn
the committed JSON.
- Lower the workflow timeout to 60 minutes; add a full_scan dispatch input.
Also fixes skills/genomic-intelligence/SKILL.md, whose unquoted description
contained a colon-space that made its YAML frontmatter invalid. The loader had
been rejecting it silently, so every scan covered 149 of 150 skills.
- Enhanced the README to clarify the publication of security scan results to a dedicated markdown file.
- Modified `scan_skills.py` to generate both a human-readable report and a machine-readable JSON report, ensuring consistency checks before CI publishing.
- Updated the GitHub Actions workflow to validate the scan report and commit the new reports, replacing the previous SECURITY.md approach with separate report files.
This change improves the clarity and accessibility of security information for users and contributors.
citation-management had no mention of Zotero despite a full pyzotero
skill existing in the repo, so agents had no path from a Zotero library
to a validated bibliography.
Adds an 'Integration with Zotero (pyzotero Skill)' section mirroring the
existing literature-review integration: pyzotero owns the library and the
BibTeX export, citation-management validates and formats, corrections
optionally written back.
Requested in #170.
Co-authored-by: Yaroslav Halchenko <debian@onerussian.com>
Found by the codespell config proposed in #123. The codespell CI check
itself was declined (52 hits on a clean checkout, only this one genuine),
but the typo it surfaced is real.
Co-authored-by: Yaroslav Halchenko <debian@onerussian.com>
Descriptors.FractionCsp3 does not exist in RDKit (verified against
2026.03.3) and raised AttributeError, causing molecular_properties.py
to fail for every input molecule. Use Lipinski.FractionCSP3, which is
already imported.
Also correct the MolToSmarts keyword in the API reference: the real
parameter is isomericSmiles, not isomericSmarts.
Both changes originate from PRs #97 and #95, which could not be merged
directly because they target the pre-rename scientific-skills/ path.
Co-authored-by: jiaodu1307 <1148451736@qq.com>