Skills
A skill is a deterministic, versioned procedure a scientist recognises: a first-in-human dose projection, an
exposure-margin table, a non-compartmental extraction of PK parameters, a SAR table, an SOP readiness check.
The same inputs give the same outputs; every intermediate value is listed; every number that comes from a
guidance document names the document, its version and the date it was retrieved. The agent orchestrates and
cites; it does not “reason” the number. Names are fixed in PRODUCT-CONTRACT.md section 12.4 and the design
is ADR 0030.
Every skill on this page is designed until the R4 gates pass: GET /skills,
GET /skills/{key} and the skill tool specifications report status: designed for every skill while
R4_GATE_PASSED = False (verified in api/app/skills/registry.py:36); flipping it is the release act after
the gate list passes. The three references of tox.fih_dose_projection were verified on 2026-09-16, so it keeps
its preview candidacy for that day; it is still served designed until the flag flips. No qualification is
claimed for any skill; outputs are inputs to a decision a person takes.
Where a skill runs and how it is recorded
Skills run on the server, never in the agent container, and every call is recorded the way every tool call is. Two classes:
- Class A (numeric and checklist skills) are server-side read tools with a typed output schema and the
function in
api/app/skills/<name>.py. They inherit the allow-list, the live permission check, thetool_callsrow, the audit row, the sanitiser and the plan gate. - Class B (library skills) run as worker jobs (
skill_library_job; the chemistry library and the dataset conformance engine are pinned there and never in the agent image), started by the server-side handler and awaited under the existing job timeout.
A skill exercises the product’s existing <product>.agents.use permission; no permission key is added. Each
call writes a tool_calls row with check_logic_version, inputs_hash, result_artifact_id and
output_violations. A skill started from the workbench needs no model: POST /programs/{program_id}/skill-runs
runs synchronously and stores a skill_result artifact with no run (run_id NULL, the persona_brief
precedent). There is no skill_run run kind; run kinds stay 13 and artifact kinds become 12.
The result shape, SkillResult, is {skill_key, check_logic_version, inputs_hash, outputs, citations[], warnings[], reference_refs[], guidance_version, retrieved_on}; every output value carries its unit in UCUM
and display form. On screen a skill output reads “Method: <name> (<guidance>, retrieved <date>), version
n” with a “How this was computed” section listing the intermediate values and the rules applied.
Vocabulary layer
Every skill input passes through api/app/skills/vocab.py: UCUM unit codes with conversion tables (mass,
concentration, AUC, dose per kg and per m²), species with default body weights and km factors, routes, dose
forms, analyte and matrix labels. A value without a unit is refused 422 unit_required, and the error sits
beside the unit field; nothing typed is lost.
Reference gate
Guidance constants live in api/app/skills/references.json, one entry per reference:
{key, url, sha256, retrieved_on, version, supersession, constants, status: verified | to_verify}.
skill-references-check runs in the API’s make check and in the release check and fails when a preview or
available skill references a to_verify entry. Every output names the guidance version and the retrieval
date, so a table computed under a superseded version says so.
Verified on 2026-09-16, 5 of 13 entries (the gate prints 5/13 references verified): fda_2005_mrsd,
ema_2017_fih and ich_m3r2 (their sha256 values are in CLAIMS-REGISTER.md) and the two repo-internal
entries assertion_model and sop_binding_rule. Still to_verify: pk_golden_synthetic_one_compartment and
the seven R5 entries (ich_m10, ich_q1a_r2, ich_q2_r2_q14, ich_q9_r1_m4q_r1, fda_oos_2022,
data_integrity_guidances, cfr_312_23). Fact (verified in api/app/skills/references.json, 13 entries, 5
verified) | Consequence: any page quoting six verified references reads five.
The R4 skills
| Skill key | Product; run role; owning workbench role | Class | Inputs (cited where marked) | Output and fixed phrases | Reference document |
|---|---|---|---|---|---|
tox.fih_dose_projection | Evidence; evidence; dmpk_tox_scientist | A | NOAEL per species with units (cited), species, body weights, safety factor (default 10), route; a species other than the most sensitive is a required human input with a rationale | HED per species, MRSD with the most sensitive species as default, the km table used; header “Projection for your decision, not a starting dose”; warnings “PAD/MABEL not computed” and “exposure-based projection not computed” | FDA 2005 MRSD guidance (km factors; verified 2026-09-16); EMA 2017 FIH guideline, Rev. 1 (verified 2026-09-16); the M3(R2) exposure clause (verified 2026-09-16); version and retrieval date from references.json |
tox.exposure_margin_table | Evidence; evidence; dmpk_tox_scientist | A | NOAEL AUC and Cmax per species (cited), projected human exposures (cited) | margins per species and endpoint as fold; units checked | arithmetic; no guidance constant |
tox.pk_parameter_extraction | Evidence; evidence; dmpk_tox_scientist | A | table rows read through documents.read_table_rows or typed rows only; dose, route; explicit lambda_z_rule (default: best-fit adjusted R², at least three terminal points) and blq_rule (default: zero before Cmax, missing after), units | Cmax, Tmax, AUC to the last point (linear-up, log-down), AUC to infinity, half-life with the points used, CL/F, Vz/F; the output states the rules applied | golden test against pk_golden_synthetic_one_compartment: a constructed one-compartment dataset with analytically known parameters, to_verify against a published dataset; the skill intends designed until one is cited (recorded 2026-09-16) |
chem.sar_table_build | Evidence; evidence; medicinal_chemist | B (chemistry library pinned) | compounds, activity records (cited) | a comparison_table with R-groups, potency, selectivity, ligand efficiency measures, properties, and a source and licence chip per cell; a share-alike line when any share-alike row is mixed in | none |
evidence.assertion_lint | Evidence; evidence; all | A | draft text | assertion kinds tagged, uncited interpretations flagged; runs before every evidence.propose_* | the assertion model |
qa.check_readiness | Review; review; qa_reviewer | A | a check and its accepted requirement set | rows met and not met with SOP anchors | extends the container-local SOP binding, which is retired when this skill lands |
Every skill key is <namespace>.<leaf> and constructs a read tool without tripping the forbidden-verb test. One
consequence shapes three later names: the test rejects any leaf that contains a forbidden verb as a
substring, so sign matches design, and the R5 skills are spelled tox.glp_tox_study_checklist,
cmc.stability_study_plan and stats.study_adequacy_check.
Reserved for R5 and R6
Keys are fixed now so the tests can assert them; nothing below exists in code in R4 and nothing is presented as live.
| Skill key | Product; owning workbench role | Class | Reference | Release |
|---|---|---|---|---|
chem.property_profile | Evidence; medicinal_chemist | B | rule set and MPO source to verify | R5 |
tox.glp_tox_study_checklist | Plans; dmpk_tox_scientist | A | M3(R2) sections (to verify) | R5 |
dmpk.bioanalytical_method_checklist | Plans; dmpk_tox_scientist | A | M10 (to verify) | R5 |
bio.target_dossier, bio.assay_readiness_checklist | Evidence; biologist_pharmacologist, computational_biologist | A | fixed order | R5 |
cmc.stability_study_plan | Plans; analytical_qc_scientist, cmc_process_scientist | A | Q1A(R2) (under revision; to verify) | R5 |
cmc.method_suitability_checklist | Plans; analytical_qc_scientist | A | Q2(R2), Q14 | R5 |
cmc.oos_oot_classification | Evidence; analytical_qc_scientist (hand-off to QA) | A | FDA OOS guidance (2006, revised 2022; sha to verify); output “investigation phase and candidate class” | R5 |
formulation.excipient_compatibility_checklist, formulation.tox_formulation_check | Plans; formulation_scientist | A | fixed checklist; precedent through clinical.get_label_metadata | R5 |
cmc.qbd_risk_table, cmc.ctd_module3_outline | Plans; cmc_process_scientist | A | Q9(R1), M4Q(R1) | R5 |
reg.ind_module_outline, reg.citation_completeness | Plans; medical_writer | A | 21 CFR 312.23 items (text to verify) | R5 |
reg.agency_question_log, reg.guidance_delta | Evidence; regulatory_strategist | A | guidance references | R5 |
qa.deviation_classification_rubric | Review; qa_reviewer | A | versioned rubric | R5 |
qa.data_integrity_checklist | Review; qa_reviewer | A | FDA 2018 data integrity guidance, MHRA 2018 GxP data integrity guidance, PIC/S PI 041 (to verify); rows attributable, legible, contemporaneous, original, accurate, complete, consistent, enduring, available; output “checked against <document> <version>”, never “data integrity assured” | R5 |
stats.study_adequacy_check | Plans; biostatistician | A | none | R5 |
clinical.trial_precedent_scan | Evidence; clinical_pharmacologist, regulatory_strategist | A | none | R5 |
pm.critical_path_recalc, pm.decision_log_scaffold | Progress; program_manager, portfolio_head | A | none; lens scorecards are linked, never attached as records | R5 |
portfolio.go_no_go_dossier | Progress; portfolio_head | A | none; scorecards under “Rubric views (advisory)” | R5 |
stats.send_conformance_report | Plans; biostatistician | B (conformance engine) | CORE | R6 |
patent.mention_scan | Evidence; ip_analyst, medicinal_chemist | A | header “Compounds mentioned in patent documents; not claim coverage, not an opinion”; families listed “for counsel”; dedupe on family id | R6 |
PK/PD simulation stays planned for R6 as a separate worker container.
Routes and DTOs
| Route | Rule | Returns |
|---|---|---|
GET /skills | authenticated | SkillOut[] {key, name, product, run_role, permission, skill_class, check_logic_version, input_schema, output_fields[], required_citations[], references[{key, version, retrieved_on, status}], status, release}; status is designed for every skill while R4_GATE_PASSED = False |
GET /skills/{key} | authenticated | SkillOut |
POST /programs/{program_id}/skill-runs | the skill’s <product>.agents.use, checked per skill | SkillRunIn {skill_key, inputs, citations?} -> SkillResultOut {artifact_id, skill_key, check_logic_version, inputs_hash, outputs: Record<string, SkillValue>, citations[], warnings[], reference_refs[], guidance_version?, retrieved_on?, created_at} where SkillValue {value, unit_ucum?, unit_display?} |
Audit action: skill_run.start. Error codes: unit_required, unit_unsupported, unit_mismatch and
invalid_input (422 and tool refusal; each carries field so the error sits beside the input it names;
verified in api/app/skills/result.py:26-28). Budgets in a conversation: max_skill_runs_per_turn = 4.
Related
- Workbench roles for which role owns which skill.
- Harnesses for how a skill joins a run’s toolset.
- Assertion kinds for what
evidence.assertion_linttags.
Source: PRODUCT-CONTRACT.md sections 12.4, 12.7 and 12.8; PRODUCT-PLAN.md Part 9 section 4.4; api/app/tools/catalogue.py (FORBIDDEN_TOOL_VERBS and the substring check in ToolSpec.__post_init__; every key <namespace>.<leaf>); decisions/0030-skills-as-server-side-tools.md