@galaxyproject/orbit 0.0.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/LICENSE +21 -0
  3. package/README.md +760 -5
  4. package/bin/legacy-mcp-config.js +363 -0
  5. package/bin/orbit.js +810 -0
  6. package/bin/pi-extension-path.d.ts +4 -0
  7. package/bin/pi-extension-path.js +44 -0
  8. package/bin/provider-auth.d.ts +22 -0
  9. package/bin/provider-auth.js +77 -0
  10. package/bin/thinking-pref.js +38 -0
  11. package/bin/update-check.d.ts +15 -0
  12. package/bin/update-check.js +137 -0
  13. package/extensions/cli-update/index.ts +32 -0
  14. package/extensions/orbit/activity-hooks.ts +141 -0
  15. package/extensions/orbit/activity.ts +116 -0
  16. package/extensions/orbit/agent-dir.ts +11 -0
  17. package/extensions/orbit/auto-resume.ts +352 -0
  18. package/extensions/orbit/config.ts +3 -0
  19. package/extensions/orbit/confusables.ts +1 -0
  20. package/extensions/orbit/context.ts +957 -0
  21. package/extensions/orbit/dashboard-commands.ts +191 -0
  22. package/extensions/orbit/dashboard-store.ts +473 -0
  23. package/extensions/orbit/dashboard-tools.ts +1185 -0
  24. package/extensions/orbit/empty-completion.ts +99 -0
  25. package/extensions/orbit/evidence-gate.ts +1276 -0
  26. package/extensions/orbit/evidence-override-command.ts +294 -0
  27. package/extensions/orbit/exec-guard/bash-risk.ts +1408 -0
  28. package/extensions/orbit/exec-guard/gate.ts +181 -0
  29. package/extensions/orbit/exec-guard/guardian-config.ts +54 -0
  30. package/extensions/orbit/exec-guard/index.ts +1 -0
  31. package/extensions/orbit/exec-guard/model-tier.ts +36 -0
  32. package/extensions/orbit/exec-guard/path-jail.ts +54 -0
  33. package/extensions/orbit/exec-guard/policy.ts +342 -0
  34. package/extensions/orbit/exec-guard/runtime-state.ts +15 -0
  35. package/extensions/orbit/exec-guard/sensitive-read.ts +525 -0
  36. package/extensions/orbit/exec-guard/types.ts +42 -0
  37. package/extensions/orbit/execution-commands.ts +134 -0
  38. package/extensions/orbit/feedback-command.ts +81 -0
  39. package/extensions/orbit/feedback.ts +96 -0
  40. package/extensions/orbit/galaxy-api.test.ts +122 -0
  41. package/extensions/orbit/galaxy-api.ts +606 -0
  42. package/extensions/orbit/galaxy-artifact-link-guidance.ts +5 -0
  43. package/extensions/orbit/galaxy-destructive-gate.ts +113 -0
  44. package/extensions/orbit/galaxy-enrich.ts +1108 -0
  45. package/extensions/orbit/galaxy-failure.ts +101 -0
  46. package/extensions/orbit/galaxy-fixture.ts +126 -0
  47. package/extensions/orbit/galaxy-history-guard.ts +233 -0
  48. package/extensions/orbit/galaxy-job-block.ts +347 -0
  49. package/extensions/orbit/galaxy-job-ops.ts +288 -0
  50. package/extensions/orbit/galaxy-live-source.ts +929 -0
  51. package/extensions/orbit/galaxy-markdown-adapter.ts +248 -0
  52. package/extensions/orbit/galaxy-op-policy.ts +332 -0
  53. package/extensions/orbit/galaxy-ops-tools.ts +326 -0
  54. package/extensions/orbit/galaxy-output-store.ts +80 -0
  55. package/extensions/orbit/galaxy-output.ts +346 -0
  56. package/extensions/orbit/galaxy-page-binding.ts +222 -0
  57. package/extensions/orbit/galaxy-page-markdown-guidance.ts +15 -0
  58. package/extensions/orbit/galaxy-page-ops.ts +159 -0
  59. package/extensions/orbit/galaxy-page-sync.test.ts +417 -0
  60. package/extensions/orbit/galaxy-page-sync.ts +318 -0
  61. package/extensions/orbit/galaxy-pages-api.ts +203 -0
  62. package/extensions/orbit/galaxy-pages-sync.ts +409 -0
  63. package/extensions/orbit/galaxy-poll-guard.ts +189 -0
  64. package/extensions/orbit/galaxy-poller.ts +706 -0
  65. package/extensions/orbit/galaxy-provenance.ts +623 -0
  66. package/extensions/orbit/galaxy-reconcile.ts +956 -0
  67. package/extensions/orbit/galaxy-recovery.ts +176 -0
  68. package/extensions/orbit/galaxy-repeat-guard.ts +55 -0
  69. package/extensions/orbit/galaxy-submission-capture.ts +707 -0
  70. package/extensions/orbit/galaxy-submission.ts +502 -0
  71. package/extensions/orbit/galaxy-tool-source.ts +78 -0
  72. package/extensions/orbit/galaxy-tool-wrap.ts +234 -0
  73. package/extensions/orbit/galaxy-udt-block.ts +127 -0
  74. package/extensions/orbit/galaxy-upload-tus.ts +334 -0
  75. package/extensions/orbit/galaxy-upload.ts +300 -0
  76. package/extensions/orbit/galaxy-version-capture.ts +65 -0
  77. package/extensions/orbit/git.ts +173 -0
  78. package/extensions/orbit/harness-block-fields.ts +597 -0
  79. package/extensions/orbit/index.ts +593 -0
  80. package/extensions/orbit/init-gate.ts +284 -0
  81. package/extensions/orbit/instructions-command.ts +136 -0
  82. package/extensions/orbit/invocation-failure-hint.ts +57 -0
  83. package/extensions/orbit/iwc-plan-check.ts +94 -0
  84. package/extensions/orbit/lesson-command.ts +303 -0
  85. package/extensions/orbit/lesson-hint.ts +245 -0
  86. package/extensions/orbit/lesson-nudge.ts +106 -0
  87. package/extensions/orbit/lessons/compose.ts +177 -0
  88. package/extensions/orbit/lessons/counters.ts +120 -0
  89. package/extensions/orbit/lessons/enabled.ts +116 -0
  90. package/extensions/orbit/lessons/matcher.ts +346 -0
  91. package/extensions/orbit/lessons/paths.ts +286 -0
  92. package/extensions/orbit/lessons/pi-event-contract.ts +105 -0
  93. package/extensions/orbit/lessons/propose-replay.ts +103 -0
  94. package/extensions/orbit/lessons/propose-tool.ts +222 -0
  95. package/extensions/orbit/lessons/propose.ts +502 -0
  96. package/extensions/orbit/lessons/replay.ts +89 -0
  97. package/extensions/orbit/lessons/reproduction-index.ts +83 -0
  98. package/extensions/orbit/lessons/search-tool.ts +99 -0
  99. package/extensions/orbit/lessons/search.ts +136 -0
  100. package/extensions/orbit/lessons/store.ts +415 -0
  101. package/extensions/orbit/lessons/text.ts +36 -0
  102. package/extensions/orbit/lessons/types.ts +69 -0
  103. package/extensions/orbit/lessons/user-dir.ts +24 -0
  104. package/extensions/orbit/lessons/user-lesson.ts +88 -0
  105. package/extensions/orbit/lessons/wrapper.ts +61 -0
  106. package/extensions/orbit/lessons-command.ts +147 -0
  107. package/extensions/orbit/local-exec.ts +39 -0
  108. package/extensions/orbit/mcp-output.ts +179 -0
  109. package/extensions/orbit/mcp-servers.test.ts +24 -0
  110. package/extensions/orbit/mcp-servers.ts +25 -0
  111. package/extensions/orbit/model-script.ts +351 -0
  112. package/extensions/orbit/notebook-anchors.ts +342 -0
  113. package/extensions/orbit/notebook-writer.ts +863 -0
  114. package/extensions/orbit/observation-allowlists.ts +1109 -0
  115. package/extensions/orbit/observation-replay.ts +148 -0
  116. package/extensions/orbit/observation-triggers.ts +563 -0
  117. package/extensions/orbit/observation-ui.ts +175 -0
  118. package/extensions/orbit/observations-command.ts +421 -0
  119. package/extensions/orbit/observations-config.ts +200 -0
  120. package/extensions/orbit/observations.ts +1381 -0
  121. package/extensions/orbit/profiles.ts +270 -0
  122. package/extensions/orbit/progress-updates.ts +95 -0
  123. package/extensions/orbit/proposal-commands.ts +882 -0
  124. package/extensions/orbit/provenance-fs-file.ts +59 -0
  125. package/extensions/orbit/provenance-fs.ts +32 -0
  126. package/extensions/orbit/provenance-memory-fs.ts +59 -0
  127. package/extensions/orbit/record-store-file.ts +177 -0
  128. package/extensions/orbit/record-store-page.ts +77 -0
  129. package/extensions/orbit/record-store-seam.ts +47 -0
  130. package/extensions/orbit/record-store.ts +149 -0
  131. package/extensions/orbit/registry-carrier.ts +107 -0
  132. package/extensions/orbit/registry-eligibility.ts +95 -0
  133. package/extensions/orbit/registry-evaluation.ts +403 -0
  134. package/extensions/orbit/registry-evaluator.ts +519 -0
  135. package/extensions/orbit/registry-import.ts +91 -0
  136. package/extensions/orbit/registry-lock.ts +221 -0
  137. package/extensions/orbit/registry-memory-fs.ts +42 -0
  138. package/extensions/orbit/registry-page-carrier.ts +103 -0
  139. package/extensions/orbit/registry-proposal.ts +1348 -0
  140. package/extensions/orbit/registry-runtime.ts +234 -0
  141. package/extensions/orbit/registry-schema.ts +735 -0
  142. package/extensions/orbit/registry-submitter.ts +59 -0
  143. package/extensions/orbit/registry-templates.ts +346 -0
  144. package/extensions/orbit/registry.ts +476 -0
  145. package/extensions/orbit/sandbox/index.ts +120 -0
  146. package/extensions/orbit/sandbox/sandbox-bash.ts +93 -0
  147. package/extensions/orbit/sandbox/sandbox-config.ts +87 -0
  148. package/extensions/orbit/sandbox/sandbox-init-message.ts +28 -0
  149. package/extensions/orbit/secret-redaction.ts +247 -0
  150. package/extensions/orbit/session-index/cwd.ts +18 -0
  151. package/extensions/orbit/session-index/db.ts +56 -0
  152. package/extensions/orbit/session-index/indexer.ts +154 -0
  153. package/extensions/orbit/session-index/is-enabled.ts +17 -0
  154. package/extensions/orbit/session-index/parse.ts +254 -0
  155. package/extensions/orbit/session-index/query.ts +209 -0
  156. package/extensions/orbit/session-index/schema.ts +72 -0
  157. package/extensions/orbit/session-index/tools.ts +152 -0
  158. package/extensions/orbit/session-lifecycle.ts +321 -0
  159. package/extensions/orbit/skill-triggers.ts +159 -0
  160. package/extensions/orbit/skills-command.ts +48 -0
  161. package/extensions/orbit/skills-discovery.ts +435 -0
  162. package/extensions/orbit/skills.ts +84 -0
  163. package/extensions/orbit/sra-import-gate.ts +77 -0
  164. package/extensions/orbit/state.ts +265 -0
  165. package/extensions/orbit/submission-replay.ts +147 -0
  166. package/extensions/orbit/sync-command.ts +157 -0
  167. package/extensions/orbit/teams/critic-parser.ts +93 -0
  168. package/extensions/orbit/teams/dispatcher.ts +210 -0
  169. package/extensions/orbit/teams/is-enabled.ts +22 -0
  170. package/extensions/orbit/teams/tool.ts +187 -0
  171. package/extensions/orbit/teams/types.ts +57 -0
  172. package/extensions/orbit/teams/validate.ts +42 -0
  173. package/extensions/orbit/tester-id-command.ts +133 -0
  174. package/extensions/orbit/tools-sync.ts +279 -0
  175. package/extensions/orbit/tools.ts +1300 -0
  176. package/extensions/orbit/types.ts +41 -0
  177. package/extensions/orbit/ui-bridge.ts +55 -0
  178. package/extensions/orbit/ulid.ts +60 -0
  179. package/extensions/orbit/user-instructions.ts +388 -0
  180. package/extensions/orbit/vendor/skills/_catalog.json +68 -0
  181. package/extensions/orbit/vendor/skills/_manifest.json +1106 -0
  182. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/SKILL.md +112 -0
  183. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_provenance.json +218 -0
  184. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_required_tools.json +33 -0
  185. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_verify.json +4 -0
  186. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/add.json +50 -0
  187. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-extract.json +51 -0
  188. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-next-step.json +42 -0
  189. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-validate.json +140 -0
  190. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/list.json +32 -0
  191. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/notes/galaxy-tool-job-failure-reference.md +137 -0
  192. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/notes/open-requirements-ledger.md +173 -0
  193. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/schemas/galaxy-tool-summary.schema.json +175 -0
  194. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/schemas/galaxy-workflow-draft.schema.json +2727 -0
  195. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/SKILL.md +82 -0
  196. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_provenance.json +133 -0
  197. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_required_tools.json +16 -0
  198. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_verify.json +4 -0
  199. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/cli/draft-validate.json +140 -0
  200. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/notes/galaxy-workflow-draft-format.md +135 -0
  201. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/notes/open-requirements-ledger.md +173 -0
  202. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/schemas/galaxy-workflow-draft.schema.json +2727 -0
  203. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/SKILL.md +84 -0
  204. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/_provenance.json +166 -0
  205. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/_verify.json +29 -0
  206. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/galaxy-workflow-testability-design.md +136 -0
  207. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  208. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/iwc-test-data-conventions.md +308 -0
  209. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/planemo-asserts-idioms.md +246 -0
  210. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/planemo-workflow-test-architecture.md +151 -0
  211. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/galaxy-workflow-test-plan.schema.json +552 -0
  212. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/summary-galaxy-workflow.schema.json +687 -0
  213. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/tests-format.schema.json +7328 -0
  214. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/SKILL.md +127 -0
  215. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_provenance.json +198 -0
  216. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_required_tools.json +16 -0
  217. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_verify.json +4 -0
  218. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/cli/convert.json +123 -0
  219. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/galaxy-data-flow-draft-contract.md +129 -0
  220. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  221. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/iwc-test-data-conventions.md +308 -0
  222. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/open-requirements-ledger.md +173 -0
  223. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/SKILL.md +73 -0
  224. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/_provenance.json +160 -0
  225. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/_verify.json +4 -0
  226. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-collection-semantics.md +43 -0
  227. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-collection-semantics.yml +1250 -0
  228. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-tool-job-failure-reference.md +137 -0
  229. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
  230. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  231. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/nextflow-operators-to-galaxy-collection-recipes.md +98 -0
  232. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/planemo-asserts-idioms.md +246 -0
  233. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/planemo-workflow-test-architecture.md +151 -0
  234. package/extensions/orbit/vendor/skills/discover-shed-tool/SKILL.md +174 -0
  235. package/extensions/orbit/vendor/skills/discover-shed-tool/_provenance.json +130 -0
  236. package/extensions/orbit/vendor/skills/discover-shed-tool/_required_tools.json +18 -0
  237. package/extensions/orbit/vendor/skills/discover-shed-tool/_verify.json +17 -0
  238. package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-revisions.json +48 -0
  239. package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-search.json +95 -0
  240. package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-versions.json +39 -0
  241. package/extensions/orbit/vendor/skills/discover-shed-tool/references/notes/component-tool-shed-search.md +230 -0
  242. package/extensions/orbit/vendor/skills/discover-shed-tool/references/schemas/galaxy-tool-discovery.schema.json +231 -0
  243. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/SKILL.md +93 -0
  244. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_provenance.json +201 -0
  245. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_required_tools.json +28 -0
  246. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_verify.json +17 -0
  247. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/cli/planemo.md +44 -0
  248. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/cli/validate-tests.json +40 -0
  249. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/galaxy-workflow-testability-design.md +136 -0
  250. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  251. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/iwc-test-data-conventions.md +308 -0
  252. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/planemo-asserts-idioms.md +246 -0
  253. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/planemo-workflow-test-architecture.md +151 -0
  254. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/schemas/galaxy-workflow-test-plan.schema.json +552 -0
  255. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/schemas/tests-format.schema.json +7328 -0
  256. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/SKILL.md +81 -0
  257. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/_provenance.json +93 -0
  258. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/_verify.json +17 -0
  259. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/references/notes/open-requirements-ledger.md +173 -0
  260. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/references/schemas/summary-galaxy-workflow.schema.json +687 -0
  261. package/extensions/orbit/vendor/skills/pipeline-update-interview-to-galaxy/SKILL.md +81 -0
  262. package/extensions/orbit/vendor/skills/pipeline-update-interview-to-galaxy/_assembly.json +23 -0
  263. package/extensions/orbit/vendor/skills/run-workflow-test/SKILL.md +79 -0
  264. package/extensions/orbit/vendor/skills/run-workflow-test/_provenance.json +125 -0
  265. package/extensions/orbit/vendor/skills/run-workflow-test/_required_tools.json +28 -0
  266. package/extensions/orbit/vendor/skills/run-workflow-test/_verify.json +4 -0
  267. package/extensions/orbit/vendor/skills/run-workflow-test/references/cli/planemo.md +44 -0
  268. package/extensions/orbit/vendor/skills/run-workflow-test/references/cli/validate-tests.json +40 -0
  269. package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
  270. package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/planemo-asserts-idioms.md +246 -0
  271. package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/planemo-workflow-test-architecture.md +151 -0
  272. package/extensions/orbit/vendor/skills/run-workflow-test/references/schemas/tests-format.schema.json +7328 -0
  273. package/extensions/orbit/vendor/skills/skills/LICENSE +21 -0
  274. package/extensions/orbit/vendor/skills/skills/collection-manipulation/README.md +39 -0
  275. package/extensions/orbit/vendor/skills/skills/collection-manipulation/SKILL.md +892 -0
  276. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/api-patterns.md +927 -0
  277. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/apply-rules.md +1482 -0
  278. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/test-patterns.md +996 -0
  279. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/tools.md +609 -0
  280. package/extensions/orbit/vendor/skills/skills/galaxy-data-libraries/SKILL.md +170 -0
  281. package/extensions/orbit/vendor/skills/skills/galaxy-integration/README.md +162 -0
  282. package/extensions/orbit/vendor/skills/skills/galaxy-integration/SKILL.md +99 -0
  283. package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/README.md +119 -0
  284. package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/tool-checking.md +419 -0
  285. package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/workflow-testing.md +617 -0
  286. package/extensions/orbit/vendor/skills/skills/galaxy-integration/galaxy-integration.md +614 -0
  287. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/SKILL.md +144 -0
  288. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/average_col3.ipynb +68 -0
  289. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/extract_sample_metadata.ipynb +190 -0
  290. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/variant_annotation.ipynb +816 -0
  291. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/vcp_variant_map.ipynb +443 -0
  292. package/extensions/orbit/vendor/skills/skills/galaxy-integration/scripts/README.md +165 -0
  293. package/extensions/orbit/vendor/skills/skills/galaxy-integration/scripts/galaxy_tool_checker.py +521 -0
  294. package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/SKILL.md +128 -0
  295. package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/gotchas.md +135 -0
  296. package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/history-access.md +132 -0
  297. package/extensions/orbit/vendor/skills/skills/reproduciblify/SKILL.md +146 -0
  298. package/extensions/orbit/vendor/skills/skills/reproduciblify/references/directives.yml +496 -0
  299. package/extensions/orbit/vendor/skills/skills/udt-authoring/SKILL.md +245 -0
  300. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/01-minimal-echo.yml +27 -0
  301. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/02-single-data-in-out.yml +27 -0
  302. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/03-multiple-data-js.yml +28 -0
  303. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/04-select-integer-boolean.yml +41 -0
  304. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/05-resource-requirements.yml +25 -0
  305. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/06-biocontainer-tool.yml +38 -0
  306. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/07-inline-python-script.yml +56 -0
  307. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/08-configfile-script.yml +74 -0
  308. package/extensions/orbit/vendor/skills/skills/udt-authoring/references/common-mistakes.md +76 -0
  309. package/extensions/orbit/vendor/skills/skills/udt-authoring/references/schema-reference.md +155 -0
  310. package/extensions/orbit/vendor/skills/skills/udt-authoring/references/templating.md +196 -0
  311. package/extensions/orbit/vendor/skills/skills/udt-authoring/scripts/validate.py +109 -0
  312. package/extensions/orbit/vendor/skills/skills/workflow-reports/README.md +71 -0
  313. package/extensions/orbit/vendor/skills/skills/workflow-reports/SKILL.md +190 -0
  314. package/extensions/orbit/vendor/skills/skills/workflow-reports/examples/histology-staining.md +145 -0
  315. package/extensions/orbit/vendor/skills/skills/workflow-reports/examples/tissue-microarray-analysis.md +176 -0
  316. package/extensions/orbit/vendor/skills/skills/workflow-reports/references/directives.md +415 -0
  317. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/SKILL.md +98 -0
  318. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_provenance.json +93 -0
  319. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_required_tools.json +28 -0
  320. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_verify.json +17 -0
  321. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/convert.json +123 -0
  322. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/foundry.md +25 -0
  323. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/validate.json +142 -0
  324. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/schemas/summary-galaxy-workflow.schema.json +687 -0
  325. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/SKILL.md +74 -0
  326. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_provenance.json +71 -0
  327. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_required_tools.json +16 -0
  328. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_verify.json +4 -0
  329. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/cli/validate.json +142 -0
  330. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
  331. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/notes/galaxy-workflow-testability-design.md +136 -0
  332. package/extensions/orbit/vendor-skills.ts +283 -0
  333. package/extensions/orbit/workspace-state-dir.ts +46 -0
  334. package/extensions/orbit-handoff/index.ts +73 -0
  335. package/extensions/orbit-handoff/orbit-launcher.ts +142 -0
  336. package/extensions/whats-new/index.ts +98 -0
  337. package/lessons/LICENSE +17 -0
  338. package/lessons/README.md +117 -0
  339. package/lessons/SCHEMA.md +187 -0
  340. package/lessons/build-snapshot.mjs +311 -0
  341. package/lessons/data/downloaded-file-is-not-what-its-extension-says.md +61 -0
  342. package/lessons/galaxy-api/403-history-is-a-hard-stop.md +57 -0
  343. package/lessons/galaxy-api/collection-into-single-dataset-input.md +61 -0
  344. package/lessons/galaxy-api/connectedvalue-in-command-line.md +62 -0
  345. package/lessons/galaxy-api/hid-is-not-an-id.md +59 -0
  346. package/lessons/galaxy-api/invoke-workflow-inputs-not-params.md +60 -0
  347. package/lessons/galaxy-api/repeat-param-pipe-keys.md +63 -0
  348. package/lessons/galaxy-api/run-tool-returns-on-submit.md +61 -0
  349. package/lessons/galaxy-tools/reference-index-not-on-server.md +62 -0
  350. package/lessons/log.md +42 -0
  351. package/lessons/reproduction/input-population-mismatch.md +59 -0
  352. package/lessons/reproduction/methods-text-vs-executed-parameters.md +62 -0
  353. package/lessons/snapshot.json +1004 -0
  354. package/lessons/stats/de-contrast-direction-and-sample-labels.md +63 -0
  355. package/lessons/stats/na-coerced-to-zero-in-filters.md +59 -0
  356. package/lessons/validate.mjs +1219 -0
  357. package/package.json +103 -5
  358. package/shared/agent-prompt.d.ts +8 -0
  359. package/shared/agent-prompt.js +15 -0
  360. package/shared/approval-prompt.d.ts +4 -0
  361. package/shared/approval-prompt.js +61 -0
  362. package/shared/brain-env.d.ts +14 -0
  363. package/shared/brain-env.js +108 -0
  364. package/shared/brain-exit.d.ts +20 -0
  365. package/shared/brain-exit.js +149 -0
  366. package/shared/capability-profile.d.ts +16 -0
  367. package/shared/capability-profile.js +75 -0
  368. package/shared/config-source.d.ts +13 -0
  369. package/shared/config-source.js +17 -0
  370. package/shared/confusables.d.ts +3 -0
  371. package/shared/confusables.js +93 -0
  372. package/shared/custom-provider.d.ts +45 -0
  373. package/shared/custom-provider.js +169 -0
  374. package/shared/dashboard-contract.d.ts +123 -0
  375. package/shared/dashboard-contract.js +560 -0
  376. package/shared/dashboard-layout-store.d.ts +44 -0
  377. package/shared/dashboard-layout-store.js +281 -0
  378. package/shared/feedback-contract.d.ts +61 -0
  379. package/shared/feedback-contract.js +146 -0
  380. package/shared/galaxy-artifact-links.d.ts +30 -0
  381. package/shared/galaxy-artifact-links.js +166 -0
  382. package/shared/galaxy-credentials.d.ts +26 -0
  383. package/shared/galaxy-credentials.js +71 -0
  384. package/shared/galaxy-destructive.d.ts +21 -0
  385. package/shared/galaxy-destructive.js +269 -0
  386. package/shared/galaxy-guidance.d.ts +2 -0
  387. package/shared/galaxy-guidance.js +53 -0
  388. package/shared/galaxy-live-contract.d.ts +92 -0
  389. package/shared/galaxy-live-contract.js +180 -0
  390. package/shared/galaxy-page-cells.d.ts +2 -0
  391. package/shared/galaxy-page-cells.js +22 -0
  392. package/shared/galaxy-tool-family.d.ts +5 -0
  393. package/shared/galaxy-tool-family.js +27 -0
  394. package/shared/galaxy-url.d.ts +1 -0
  395. package/shared/galaxy-url.js +48 -0
  396. package/shared/gtn.d.ts +31 -0
  397. package/shared/gtn.js +253 -0
  398. package/shared/handled-prompt.d.ts +3 -0
  399. package/shared/handled-prompt.js +26 -0
  400. package/shared/known-provider.d.ts +11 -0
  401. package/shared/known-provider.js +89 -0
  402. package/shared/lesson-hint-marker.d.ts +7 -0
  403. package/shared/lesson-hint-marker.js +32 -0
  404. package/shared/lesson-rules.d.ts +150 -0
  405. package/shared/lesson-rules.js +203 -0
  406. package/shared/malformed-object-ids.d.ts +1 -0
  407. package/shared/malformed-object-ids.js +37 -0
  408. package/shared/markdown-sections.d.ts +10 -0
  409. package/shared/markdown-sections.js +118 -0
  410. package/shared/notebook-fences.d.ts +12 -0
  411. package/shared/notebook-fences.js +53 -0
  412. package/shared/observation-contract.d.ts +91 -0
  413. package/shared/observation-contract.js +544 -0
  414. package/shared/orbit-config.d.ts +226 -0
  415. package/shared/orbit-config.js +189 -0
  416. package/shared/orbit-env.d.ts +13 -0
  417. package/shared/orbit-env.js +124 -0
  418. package/shared/orbit-shell-contract.d.ts +74 -0
  419. package/shared/orbit-shell-contract.js +30 -0
  420. package/shared/page-content-hash.d.ts +1 -0
  421. package/shared/page-content-hash.js +13 -0
  422. package/shared/pi-default-model.d.ts +7 -0
  423. package/shared/pi-default-model.js +41 -0
  424. package/shared/prompt-blocks.d.ts +87 -0
  425. package/shared/prompt-blocks.js +898 -0
  426. package/shared/provider-auth-caps.d.ts +22 -0
  427. package/shared/provider-auth-caps.js +57 -0
  428. package/shared/random.d.ts +2 -0
  429. package/shared/random.js +15 -0
  430. package/shared/record-excerpt.d.ts +4 -0
  431. package/shared/record-excerpt.js +16 -0
  432. package/shared/redirect-guard.d.ts +36 -0
  433. package/shared/redirect-guard.js +235 -0
  434. package/shared/skills-pin.d.ts +8 -0
  435. package/shared/skills-pin.js +9 -0
  436. package/shared/skills-router.d.ts +17 -0
  437. package/shared/skills-router.js +63 -0
  438. package/shared/sra-import.d.ts +34 -0
  439. package/shared/sra-import.js +206 -0
  440. package/shared/state-dir.d.ts +21 -0
  441. package/shared/state-dir.js +240 -0
  442. package/shared/team-dispatch-contract.d.ts +28 -0
  443. package/shared/team-dispatch-contract.js +1 -0
  444. package/shared/truncate-middle.d.ts +11 -0
  445. package/shared/truncate-middle.js +68 -0
  446. package/shared/version-compare.d.ts +10 -0
  447. package/shared/version-compare.js +74 -0
  448. package/shared/whats-new.d.ts +31 -0
  449. package/shared/whats-new.js +83 -0
  450. package/shared/wsl.d.ts +10 -0
  451. package/shared/wsl.js +24 -0
@@ -0,0 +1,245 @@
1
+ ---
2
+ name: udt-authoring
3
+ description: "Use when authoring a Galaxy User-Defined Tool (UDT) -- a `class: GalaxyUserTool` YAML definition that wraps a container and command into a tool a non-admin user creates and runs (e.g. via Galaxy MCP create_user_tool / run_user_tool, or POST /api/unprivileged_tools). Not for classic XML/ToolShed tool wrappers."
4
+ metadata:
5
+ surfaces: [loom]
6
+ version: 1.1.0
7
+ tags: [galaxy, tools, udt, user-defined-tools, custom-tool]
8
+ ---
9
+
10
+ # Authoring Galaxy User-Defined Tools (UDTs)
11
+
12
+ A **User-Defined Tool (UDT)** is a tool that a regular (non-admin) Galaxy user defines in YAML
13
+ and runs unprivileged, introduced in Galaxy 25.0. It is declared with `class: GalaxyUserTool` and
14
+ validated against the `UserToolSource` schema. This skill is the reference for producing a correct,
15
+ lint-clean definition.
16
+
17
+ ## When to Use
18
+
19
+ - The user wants to wrap a command + container as a runnable Galaxy tool they own.
20
+ - Triggers: "make me a Galaxy tool that runs X", "wrap this command as a UDT", "create a custom
21
+ tool", "register a tool in my account".
22
+ - You are an external agent (Loom, an MCP client, a notebook) that will create/run the tool via
23
+ `create_user_tool` / `run_user_tool` or `POST /api/unprivileged_tools`.
24
+
25
+ **When NOT to use:** classic XML / ToolShed tool wrappers (Cheetah templating, `tools-iuc`
26
+ submission) -- that is a different format; use the `tool-dev` skill instead. A UDT is **not** XML
27
+ and does **not** use Cheetah.
28
+
29
+ ## Mental Model (read this first -- it is where agents go wrong)
30
+
31
+ A UDT = a **container** + a **`shell_command`** + typed **`inputs`** and **`outputs`**.
32
+
33
+ - The command lives under **`shell_command`** (NOT `command`).
34
+ - Parameters are interpolated with **sandboxed ECMAScript inside `$(...)`** -- NOT Cheetah `$x` and
35
+ NOT `#for#` loops. A data file's path is `$(inputs.name.path)`; a scalar value is
36
+ `$(inputs.name)`.
37
+ - The `$(...)` templating sandbox has **no database or filesystem access**. Every UDT **must run in
38
+ a container** (`container:` is a required plain string); whether that container has network access
39
+ is set by the Galaxy admin's job config, not by the tool.
40
+ - Every **dataset/collection** output must **claim a file** it produced via `from_work_dir` (one
41
+ file) or `discover_datasets` (many) -- you do not write to a templated output path.
42
+ - Scalar `text`/`select` values interpolate into `shell_command` **unquoted** (unlike `base_command`
43
+ args, which are `shlex.quote`d) -- a value with spaces or quotes breaks the command. Quote them,
44
+ or pass free text via a configfile. See `references/templating.md`.
45
+
46
+ If you find yourself writing `command:`, `$param`, `#for#`, `truevalue:`, or `${on_string}`, stop
47
+ -- those are XML/Cheetah habits the schema rejects. See `references/common-mistakes.md`.
48
+
49
+ ## Quick Reference -- minimal valid skeleton
50
+
51
+ ```yaml
52
+ class: GalaxyUserTool # required, exactly this
53
+ id: my-tool # lowercase, ^[a-z][a-z0-9_-]*$, 3-255 chars (recommended)
54
+ version: "0.1.0" # required -- schema validation rejects a versionless tool
55
+ name: My Tool # required, min 5 chars
56
+ description: One line shown in the tool menu
57
+ container: quay.io/biocontainers/seqkit:2.8.2--h9ee0642_0 # required STRING, a real image
58
+ shell_command: |
59
+ seqkit stats --tabular '$(inputs.input.path)' > stats.tsv
60
+ inputs:
61
+ - name: input
62
+ type: data
63
+ format: fastq
64
+ label: Input sequences
65
+ outputs:
66
+ - name: report
67
+ type: data
68
+ format: tabular
69
+ from_work_dir: stats.tsv # claim the file the command wrote
70
+ label: Sequence statistics
71
+ ```
72
+
73
+ Full field list, input/output types, and validator rules: **`references/schema-reference.md`**.
74
+ Templating syntax (`$(inputs.x)`, arrays, `$GALAXY_SLOTS`, escaping): **`references/templating.md`**.
75
+
76
+ ## Authoring Workflow
77
+
78
+ 1. **Understand the command.** What binary runs, what inputs it consumes, what files it produces.
79
+ 2. **Pick a real container** -- this is the #1 cause of runtime failure. Resolve a verified image
80
+ with `recommend_biocontainer` (Galaxy MCP) or the `mulled-recommend` CLI rather than guessing;
81
+ **never invent the `--<hash>_<build>` tag suffix** -- it is not predictable. For stdlib-only
82
+ logic, use an official `python:3.x-slim` image and write the code inline. **Do not invent an
83
+ image or flag you cannot verify** -- ask instead. See "Choosing a Container" below. Lint will
84
+ *not* catch a bad image; the job simply fails to pull it.
85
+ 3. **Draft the definition** using `references/schema-reference.md`. Reference each input as
86
+ `$(inputs.name.path)` (data) or `$(inputs.name)` (scalar). Write outputs to fixed filenames and
87
+ claim them with `from_work_dir` / `discover_datasets`. Always include a `help` block (convention
88
+ -- see "Write a help block" below).
89
+ 4. **Self-review** against `references/common-mistakes.md` (it doubles as a checklist).
90
+ 5. **Validate** (see below) and iterate on real errors.
91
+ 6. **Create + run.** Hand the validated definition to `create_user_tool`, then `run_user_tool`
92
+ (this skill stops at a valid definition -- the run/invocation loop is the caller's job).
93
+
94
+ ## Choosing a Container
95
+
96
+ The container is the part most likely to pass validation but fail at run time, because nothing in
97
+ the schema or lint checks that the image actually exists or pulls. A real example: a plotting UDT
98
+ that declared `quay.io/biocontainers/seaborn:0.13.2--pyhd8ed1ab_3` was accepted by
99
+ `create_user_tool`, then the job died with `manifest unknown` -- that exact build tag did not exist
100
+ on quay. Guard against it:
101
+
102
+ - **Resolve a verified image instead of guessing one -- do this first.** If a
103
+ `recommend_biocontainer` tool is available (Galaxy MCP), call it with the conda packages your
104
+ command needs -- e.g. `["samtools=1.17", "bwa"]` -- and use the `image` it returns. It's resolved
105
+ and checked against quay.io rather than hallucinated, so it can't invent a nonexistent tag. A
106
+ single package yields a single-package image; several yield a mulled-v2 image. The returned
107
+ `match_quality` tells you whether the exact version matched (`exact_version`) or only the name did
108
+ (`name_only`, newest tag used), and `verified` confirms the tag is actually built. Only auto-apply
109
+ an `exact_version` result; if it comes back `name_only` and the exact version matters, review the
110
+ substituted tag before using it. From a terminal,
111
+ the same resolver is the **`mulled-recommend`** CLI in `galaxy-tool-util`:
112
+ `mulled-recommend samtools=1.17`, `mulled-recommend --json "bwa,samtools"`.
113
+ - **If you must pick by hand, don't guess the biocontainers build suffix** (`--<hash>_<build>`). It
114
+ is not derivable from the version. Look up the real tag: browse
115
+ `https://quay.io/repository/biocontainers/<tool>?tab=tags` or query
116
+ `https://quay.io/api/v1/repository/biocontainers/<tool>/tag/?onlyActiveTags=true`.
117
+ - **For a stdlib-only tool, skip biocontainers entirely.** Use an official base image like
118
+ `python:3.11-slim` (or `busybox` for shell-only) and write the logic inline (see the heredoc
119
+ pattern in `references/templating.md`). The seaborn failure above was fixed exactly this way:
120
+ switch to `python:3.11-slim` and emit SVG with the standard library, no third-party image to get
121
+ wrong. (A bare language image ships no third-party libraries -- `python:3.13` cannot `import
122
+ pandas` -- so this is only for genuinely stdlib-only logic; otherwise resolve a package image
123
+ above.)
124
+ - **Never invent an image, tag, or CLI flag you can't verify** -- resolve it (above) or ask the user
125
+ rather than guessing.
126
+
127
+ ## Write a `help` block (convention)
128
+
129
+ `help` is schema-optional, but **always include a real one**. Galaxy renders it under the parameter
130
+ form on the tool page, so a UDT without help is a black box to anyone -- including the same user
131
+ weeks later -- who opens it. The wire shape is an object, not a bare string:
132
+
133
+ ```yaml
134
+ help:
135
+ format: markdown # markdown | restructuredtext | plain_text
136
+ content: |
137
+ Cuts a single column from a tab-separated file.
138
+
139
+ **Inputs**
140
+ - `input`: TSV file (with or without header).
141
+ - `column`: 1-based column index.
142
+
143
+ **Outputs**
144
+ - `output`: TSV with only the selected column, in input row order.
145
+
146
+ Header lines are not auto-detected; the column index applies to every row.
147
+ ```
148
+
149
+ Three short paragraphs is enough: what the tool does, its inputs/outputs, and any caveat (resource
150
+ limits, expected file shape, non-obvious behavior). Don't ship a `TODO` placeholder -- an empty or
151
+ stub `help` is no better than none. If help genuinely isn't worth writing (a one-off throwaway), say
152
+ so and confirm with the user before creating the tool.
153
+
154
+ ## Validating a Definition
155
+
156
+ Validation logic is pure Python in `galaxy-tool-util` -- the same code the server runs -- so you can
157
+ check offline before submitting. Three tiers, weakest to strongest:
158
+
159
+ 1. **Local** (fast, offline, side-effect-free): `python scripts/validate.py my-tool.yml`. Needs
160
+ `pip install 'galaxy-tool-util>=26.1'`. Catches structural errors, the four semantic validators, and
161
+ lint warnings. Use this whenever a Python env is available (terminal, CI). See `scripts/`.
162
+ **Version-sensitive:** the installed galaxy-tool-util *is* the schema, and the 26.1 behaviors this
163
+ skill describes (data inputs rejecting `min`/`max`, a minimal `discover_datasets`,
164
+ `--check-container`) need galaxy-tool-util **26.1+** -- so install
165
+ `pip install 'galaxy-tool-util>=26.1'`. On an older install the same file validates against the
166
+ older schema, which is a different answer, not a wrong one: if your target server is older, that
167
+ *is* the schema you're writing against. Either way the server create (tier 3) is the final word.
168
+ 2. **`planemo lint`** -- not available yet (planemo does not lint UDTs as of this writing). It
169
+ already depends on `galaxy-tool-util`, so teaching it to lint a `GalaxyUserTool` YAML would be a
170
+ small addition, and it's the natural future home for tier 1. Down the road `scripts/validate.py`
171
+ should migrate to `planemo lint <tool>.yml`, so authors get this check through the standard Galaxy
172
+ tool CLI instead of a bundled script. Until that lands, use tier 1.
173
+ 3. **Server create** -- `create_user_tool` / `POST /api/unprivileged_tools` runs the same lint and
174
+ confirms *this server* accepts it (needs `enable_beta_tool_formats` + the Custom Tool Execution
175
+ role). This is the final word, and the practical gate for environments without Python (e.g.
176
+ Loom): submit, then iterate on the returned errors.
177
+
178
+ > **Lint-clean is necessary but not sufficient.** Neither validate.py nor the server's create lint
179
+ > checks that the command actually succeeds. The one thing you *can* check ahead of time is the
180
+ > container: a nonexistent tag (`manifest unknown` at run time) is the most common real-world UDT
181
+ > failure, so resolve a verified image with `recommend_biocontainer` / `mulled-recommend` (see
182
+ > "Choosing a Container") -- or run `validate.py --check-container` to test the tag you already have.
183
+ > Beyond that, validation can't see runtime JS-expression errors, shell quoting, the server's
184
+ > role/config gates, or whether the command produces the declared outputs -- only running the tool
185
+ > does.
186
+
187
+ ## Iterating & Cleanup
188
+
189
+ There is no in-place update API -- every `create_user_tool` call makes a **new** tool. When you
190
+ iterate, bump `version` (e.g. `0.1.0` -> `0.2.0`); Galaxy keeps every prior version under the user's
191
+ account. Heavy iteration accumulates stale versions, so once a design stabilizes, offer to deactivate
192
+ the superseded ones with `delete_user_tool` -- it marks the tool inactive (hidden from the toolbox),
193
+ not a hard delete; the records remain.
194
+
195
+ ## Limitations
196
+
197
+ UDTs deliberately can't reach several things classic tools can (per the Galaxy docs):
198
+
199
+ - **No reference data** -- no built-in genome indexes or `.loc` files.
200
+ - **No metadata files** -- e.g. a BAM index (`.bai`) isn't available; if the command needs one, build
201
+ it inside the `shell_command` or take it as an explicit `data` input.
202
+ - **No `extra_files` directory** -- composite / extra-file outputs aren't supported.
203
+
204
+ Design around these: pass whatever the tool needs as an explicit input, and generate any side files
205
+ inside the container.
206
+
207
+ ## Common Patterns
208
+
209
+ | Goal | shell_command snippet |
210
+ |------|-----------------------|
211
+ | Single data file path | `tool '$(inputs.reads.path)'` |
212
+ | Scalar value | `tool --count $(inputs.count)` |
213
+ | Multiple data files | `cat $(inputs.datasets.map(d => d.path).join(' ')) > out.txt` |
214
+ | Boolean as a flag | `tool $(inputs.verbose ? '--verbose' : '')` |
215
+ | Use the job's allocated cores | `tool --threads $GALAXY_SLOTS` (+ a `resource` requirement, `cores_min`) |
216
+ | Capture one output file | declare output with `from_work_dir: out.txt` |
217
+ | Capture many outputs | declare output `type: collection` with `discover_datasets` |
218
+ | Run a non-trivial inline script | `python <<'PY'` ... `PY` heredoc; reference inputs as `$(inputs.x)` inside (see `references/templating.md`) |
219
+
220
+ See `examples/` for eight complete, validated UDTs spanning these patterns.
221
+
222
+ ## Troubleshooting
223
+
224
+ | Symptom / error code | Cause | Fix |
225
+ |----------------------|-------|-----|
226
+ | `dynamic_tool.output_unclaimed` | Output has no `from_work_dir`/`discover_datasets` | Write to a fixed filename and claim it |
227
+ | `dynamic_tool.undeclared_input_ref` | `$(inputs.X)` with no input named `X` | Declare the input or fix the name |
228
+ | `dynamic_tool.blank_container` | `container` empty / missing | Set a real container image string |
229
+ | `string_pattern_mismatch` on `id` | Uppercase, leading digit, spaces | Use `^[a-z][a-z0-9_-]*$` |
230
+ | extra-field rejection | XML-ism like `truevalue`, `command`, `${on_string}` | Remove it -- schema is `extra="forbid"` |
231
+ | `manifest unknown` / `Unable to find image` at **run** time | Container tag doesn't exist on the registry | Resolve a verified image with `recommend_biocontainer` / `mulled-recommend` (or `python:3.x-slim` for stdlib tools) -- lint can't catch this |
232
+ | HTTP 403 "not allowed to run unprivileged" | The admin's job routing (TPV) rejects `tool_type_user_defined` by default | Not fixable client-side -- the admin must add a destination/routing rule for user-defined tools |
233
+ | `help` rejected at create | `help` sent as a bare string | Use the object form: `help: {format, content}` |
234
+
235
+ Full list with the why behind each: `references/common-mistakes.md`.
236
+
237
+ ## Resources
238
+
239
+ - `references/schema-reference.md` -- every `UserToolSource` field, input/output types, validators
240
+ - `references/templating.md` -- the `$(...)` ECMAScript model, arrays, `$GALAXY_SLOTS`, escaping
241
+ - `references/common-mistakes.md` -- pre-submit self-review checklist
242
+ - `scripts/validate.py` -- offline validate + lint via `galaxy-tool-util`
243
+ - `examples/` -- eight complete UDTs, simple to complex (incl. inline-script and configfile-script `python:slim` tools)
244
+ - Galaxy docs: [User-Defined Tools](https://docs.galaxyproject.org/en/master/admin/user_defined_tools.html)
245
+ - For classic XML tools instead: the `tool-dev` skill.
@@ -0,0 +1,27 @@
1
+ # Smallest useful UDT: one text input, one captured output.
2
+ class: GalaxyUserTool
3
+ id: echo-message
4
+ version: "0.1.0"
5
+ name: Echo a message
6
+ description: Write a user-provided message to a text file
7
+ container: busybox
8
+ shell_command: |
9
+ echo "$(inputs.message)" > out.txt
10
+ inputs:
11
+ - name: message
12
+ type: text
13
+ value: "Hello, Galaxy!"
14
+ label: Message to write
15
+ outputs:
16
+ - name: out
17
+ type: data
18
+ format: txt
19
+ from_work_dir: out.txt
20
+ label: Message file
21
+ help:
22
+ format: markdown
23
+ content: |
24
+ Writes a user-provided message to a text file.
25
+
26
+ **Inputs** -- `message`: the text to write.
27
+ **Outputs** -- `out`: a text file containing the message.
@@ -0,0 +1,27 @@
1
+ # One data input referenced by .path, transformed, one output claimed by from_work_dir.
2
+ class: GalaxyUserTool
3
+ id: to-uppercase
4
+ version: "0.1.0"
5
+ name: Uppercase a text file
6
+ description: Convert all letters in a text file to uppercase
7
+ container: busybox
8
+ shell_command: |
9
+ tr '[:lower:]' '[:upper:]' < '$(inputs.input.path)' > upper.txt
10
+ inputs:
11
+ - name: input
12
+ type: data
13
+ format: txt
14
+ label: Input text file
15
+ outputs:
16
+ - name: output
17
+ type: data
18
+ format: txt
19
+ from_work_dir: upper.txt
20
+ label: Uppercased text
21
+ help:
22
+ format: markdown
23
+ content: |
24
+ Converts all letters in a text file to uppercase.
25
+
26
+ **Inputs** -- `input`: a text file.
27
+ **Outputs** -- `output`: the same text, uppercased.
@@ -0,0 +1,28 @@
1
+ # A multiple:true data input is an array -- map over it to build the command.
2
+ # format_source copies the output datatype from an input instead of hardcoding it.
3
+ class: GalaxyUserTool
4
+ id: concatenate-files
5
+ version: "0.1.0"
6
+ name: Concatenate files
7
+ description: Concatenate one or more files head-to-tail
8
+ container: busybox
9
+ shell_command: |
10
+ cat $(inputs.datasets.map((input) => input.path).join(' ')) > output.txt
11
+ inputs:
12
+ - name: datasets
13
+ type: data
14
+ multiple: true
15
+ label: Files to concatenate
16
+ outputs:
17
+ - name: output
18
+ type: data
19
+ format_source: datasets
20
+ from_work_dir: output.txt
21
+ label: Concatenated output
22
+ help:
23
+ format: markdown
24
+ content: |
25
+ Concatenates one or more files head-to-tail into a single file.
26
+
27
+ **Inputs** -- `datasets`: one or more files.
28
+ **Outputs** -- `output`: the concatenated result (datatype copied from the inputs).
@@ -0,0 +1,41 @@
1
+ # Scalar parameter types: select (with options), integer (with bounds), and a
2
+ # boolean turned into a flag via a ternary -- NOT truevalue/falsevalue.
3
+ class: GalaxyUserTool
4
+ id: repeat-greeting
5
+ version: "0.1.0"
6
+ name: Repeat a greeting
7
+ description: Print a chosen greeting a number of times, optionally shouting
8
+ container: busybox
9
+ shell_command: |
10
+ yes "$(inputs.greeting)$(inputs.shout ? '!' : '')" | head -n $(inputs.count) > greetings.txt
11
+ inputs:
12
+ - name: greeting
13
+ type: select
14
+ label: Greeting
15
+ help: Which greeting to print.
16
+ options:
17
+ - { label: Hi, value: Hi, selected: true }
18
+ - { label: Hello, value: Hello, selected: false }
19
+ - name: count
20
+ type: integer
21
+ value: 3
22
+ min: 1
23
+ max: 100
24
+ label: Number of lines
25
+ - name: shout
26
+ type: boolean
27
+ value: false
28
+ label: Add an exclamation mark
29
+ outputs:
30
+ - name: output
31
+ type: data
32
+ format: txt
33
+ from_work_dir: greetings.txt
34
+ label: Greetings
35
+ help:
36
+ format: markdown
37
+ content: |
38
+ Prints a chosen greeting a number of times, optionally with an exclamation mark.
39
+
40
+ **Inputs** -- `greeting` (Hi/Hello), `count` (1-100), `shout` (adds "!").
41
+ **Outputs** -- `output`: the greetings, one per line.
@@ -0,0 +1,25 @@
1
+ # Request cores with a resource requirement; read the allocation at runtime via
2
+ # the $GALAXY_SLOTS shell variable (no parentheses -> not a $() expression).
3
+ class: GalaxyUserTool
4
+ id: report-cores
5
+ version: "0.1.0"
6
+ name: Report allocated cores
7
+ description: Write the number of CPU cores Galaxy allocated to this job
8
+ container: busybox
9
+ requirements:
10
+ - type: resource
11
+ cores_min: 2
12
+ shell_command: |
13
+ echo "$GALAXY_SLOTS" > galaxy_cores.txt
14
+ outputs:
15
+ - name: cores
16
+ type: data
17
+ format: txt
18
+ from_work_dir: galaxy_cores.txt
19
+ label: Allocated cores
20
+ help:
21
+ format: markdown
22
+ content: |
23
+ Reports the number of CPU cores Galaxy allocated to the job (from `$GALAXY_SLOTS`).
24
+
25
+ **Outputs** -- `cores`: a one-line text file with the core count.
@@ -0,0 +1,38 @@
1
+ # Realistic capstone: a real bioinformatics tool in a biocontainer, multiple data
2
+ # inputs joined with .map().join(), threads from $GALAXY_SLOTS, tabular output.
3
+ #
4
+ # IMPORTANT: verify the exact container tag exists before use -- do not guess.
5
+ # Browse https://quay.io/repository/biocontainers/seqkit?tab=tags for current tags.
6
+ class: GalaxyUserTool
7
+ id: seqkit-stats
8
+ version: "0.1.0"
9
+ name: SeqKit sequence statistics
10
+ description: Summary statistics (num seqs, length, N50, GC) for FASTA/FASTQ files
11
+ container: quay.io/biocontainers/seqkit:2.8.2--h9ee0642_0
12
+ requirements:
13
+ - type: resource
14
+ cores_min: 2
15
+ shell_command: |
16
+ seqkit stats --tabular --all --threads $GALAXY_SLOTS $(inputs.input_files.map((f) => f.path).join(' ')) > stats.tsv
17
+ inputs:
18
+ - name: input_files
19
+ type: data
20
+ format: [fasta, fastq]
21
+ multiple: true
22
+ label: Input sequence file(s)
23
+ help: One or more FASTA or FASTQ files to summarize.
24
+ outputs:
25
+ - name: report
26
+ type: data
27
+ format: tabular
28
+ from_work_dir: stats.tsv
29
+ label: Sequence statistics (TSV)
30
+ help:
31
+ format: markdown
32
+ content: |
33
+ Computes summary statistics (num seqs, length, N50, GC) for FASTA/FASTQ files with `seqkit stats`.
34
+
35
+ **Inputs** -- `input_files`: one or more FASTA/FASTQ files.
36
+ **Outputs** -- `report`: a tabular statistics report.
37
+
38
+ Uses the job's allocated cores (`$GALAXY_SLOTS`).
@@ -0,0 +1,56 @@
1
+ # Real-world pattern: a stdlib-only Python tool in an OFFICIAL python:3.x-slim image
2
+ # (not a biocontainer whose build-hash tag you'd have to guess), with the script
3
+ # embedded via a quoted heredoc. Modeled on a plotting UDT whose seaborn-biocontainer
4
+ # tag did not exist at run time -- switching to python:3.11-slim + stdlib was the fix.
5
+ class: GalaxyUserTool
6
+ id: column-summary
7
+ version: "0.1.0"
8
+ name: Summarize a numeric column
9
+ description: Report count, mean, min, and max of one numeric column in a tabular file
10
+ container: python:3.11-slim
11
+ shell_command: |
12
+ python <<'PY'
13
+ import csv
14
+ path = '$(inputs.table.path)'
15
+ column = '$(inputs.column)'
16
+ values = []
17
+ with open(path, newline='') as fh:
18
+ reader = csv.DictReader(fh, delimiter='\t')
19
+ for row in reader:
20
+ cell = row.get(column, '')
21
+ if cell not in ('', None):
22
+ values.append(float(cell))
23
+ if not values:
24
+ raise SystemExit(f'No numeric values found in column {column!r}')
25
+ n = len(values)
26
+ with open('summary.txt', 'w') as out:
27
+ out.write(f'column\t{column}\n')
28
+ out.write(f'count\t{n}\n')
29
+ out.write(f'mean\t{sum(values) / n}\n')
30
+ out.write(f'min\t{min(values)}\n')
31
+ out.write(f'max\t{max(values)}\n')
32
+ PY
33
+ inputs:
34
+ - name: table
35
+ type: data
36
+ format: tabular
37
+ label: Tabular input
38
+ - name: column
39
+ type: text
40
+ label: Column name to summarize
41
+ help: Must match a column header in the tabular file.
42
+ outputs:
43
+ - name: summary
44
+ type: data
45
+ format: txt
46
+ from_work_dir: summary.txt
47
+ label: Column summary
48
+ help:
49
+ format: markdown
50
+ content: |
51
+ Reports count, mean, min, and max of one numeric column in a tabular file.
52
+
53
+ **Inputs** -- `table`: a tabular file; `column`: the column header to summarize.
54
+ **Outputs** -- `summary`: a small text report.
55
+
56
+ The column must match a header in the file; non-numeric/empty cells are skipped.
@@ -0,0 +1,74 @@
1
+ # Real-world pattern: run a longer script by NAME, and pass an untrusted `text`
2
+ # parameter SAFELY. Two things to notice:
3
+ # 1. The script is materialized by a `configfiles` entry whose `filename` is
4
+ # exactly what `shell_command` runs -- the critical rule from
5
+ # references/templating.md. (`python summarize.py` with no configfile that
6
+ # creates summarize.py would be broken -- the file wouldn't exist at run time.)
7
+ # 2. The `column` value is a free-text input, so it is NOT interpolated into
8
+ # Python source (a quote or newline could break or inject into the code).
9
+ # Instead it's written to a JSON configfile via `JSON.stringify(...)` -- which
10
+ # safely encodes any string -- and the script reads it back as data.
11
+ class: GalaxyUserTool
12
+ id: column-summary-configfile
13
+ version: "0.1.0"
14
+ name: Summarize a numeric column (configfile)
15
+ description: Report count, mean, min, and max of one numeric column in a tabular file
16
+ container: python:3.11-slim
17
+ configfiles:
18
+ - filename: params.json
19
+ content: |
20
+ {"table": $(JSON.stringify(inputs.table.path)), "column": $(JSON.stringify(inputs.column))}
21
+ - filename: summarize.py
22
+ content: |
23
+ import csv
24
+ import json
25
+
26
+ with open("params.json") as fh:
27
+ params = json.load(fh)
28
+ path = params["table"]
29
+ column = params["column"]
30
+
31
+ values = []
32
+ with open(path, newline="") as fh:
33
+ for row in csv.DictReader(fh, delimiter="\t"):
34
+ cell = row.get(column, "")
35
+ try:
36
+ values.append(float(cell))
37
+ except (TypeError, ValueError):
38
+ continue # skip empty and non-numeric cells
39
+ if not values:
40
+ raise SystemExit(f"No numeric values found in column {column!r}")
41
+ n = len(values)
42
+ with open("summary.txt", "w") as out:
43
+ out.write(f"column\t{column}\n")
44
+ out.write(f"count\t{n}\n")
45
+ out.write(f"mean\t{sum(values) / n}\n")
46
+ out.write(f"min\t{min(values)}\n")
47
+ out.write(f"max\t{max(values)}\n")
48
+ shell_command: python summarize.py
49
+ inputs:
50
+ - name: table
51
+ type: data
52
+ format: tabular
53
+ label: Tabular input
54
+ - name: column
55
+ type: text
56
+ label: Column name to summarize
57
+ help: Must match a column header in the tabular file.
58
+ outputs:
59
+ - name: summary
60
+ type: data
61
+ format: txt
62
+ from_work_dir: summary.txt
63
+ label: Column summary
64
+ help:
65
+ format: markdown
66
+ content: |
67
+ Reports count, mean, min, and max of one numeric column in a tabular file.
68
+
69
+ **Inputs** -- `table`: a tabular file; `column`: the column header to summarize.
70
+ **Outputs** -- `summary`: a small text report.
71
+
72
+ The script is delivered as a configfile named `summarize.py` and run by name;
73
+ the column name is passed via a JSON configfile (not inlined into the code).
74
+ The column must match a header in the file; empty and non-numeric cells are skipped.
@@ -0,0 +1,76 @@
1
+ # Common Mistakes & Pre-Submit Checklist
2
+
3
+ UDTs are modeled after XML tools, so the most common failures are XML/Cheetah habits leaking in,
4
+ plus a few schema-specific traps. Run through this before submitting.
5
+
6
+ ## Checklist
7
+
8
+ - [ ] Command is under **`shell_command`**, not `command`.
9
+ - [ ] Parameters use **`$(inputs.x)`** / **`$(inputs.x.path)`**, not Cheetah `$x` or `#for#`.
10
+ - [ ] `container` is a **plain string** of a **real** image (verified biocontainer when possible).
11
+ - [ ] Every output has **`from_work_dir`** or **`discover_datasets`** (collections: `discover_datasets`).
12
+ - [ ] Outputs are captured by file (`from_work_dir`/`discover_datasets`); there is **no** `$(outputs.X.path)`.
13
+ - [ ] Every `$(inputs.X)` reference has a matching declared input named `X`.
14
+ - [ ] If `shell_command` runs a script by name (`python script.py`), a `configfiles` entry creates that exact filename -- otherwise inline it with `python -c` / `Rscript -e`.
15
+ - [ ] No `min`/`max` on a `data` input (it's already required; use `optional: true` to relax, `multiple: true` for a list).
16
+ - [ ] `id` matches `^[a-z][a-z0-9_-]*$`; `name` is at least 5 characters.
17
+ - [ ] No rejected fields: `truevalue`, `falsevalue`, `argument`, `parameter_type`, `${on_string}`, `${tool.name}`.
18
+ - [ ] Booleans become flags via a ternary, not `truevalue`/`falsevalue`.
19
+ - [ ] The parallelism flag's **value** is `$GALAXY_SLOTS` (+ a `resource` requirement), not a hardcoded number -- and not merely echoed to a log while the flag stays a literal.
20
+ - [ ] Optional parameters have sensible `value` defaults.
21
+ - [ ] Labels and description say what the tool actually does (not "Run the tool").
22
+ - [ ] A real `help` block is present (object form `{format, content}`, no `TODO` placeholder).
23
+ - [ ] Scalar `text`/`select` values are quoted in `shell_command` (or passed via a configfile) -- they interpolate unquoted.
24
+
25
+ ## Mistakes table
26
+
27
+ | Mistake | Why it's wrong | Fix |
28
+ |---------|----------------|-----|
29
+ | `command: ...` | The field is `shell_command`; `command` is rejected (`extra="forbid"`). | Rename to `shell_command`. |
30
+ | `$threads`, `#for f in $files#` | Cheetah templating. UDTs use sandboxed ECMAScript. | `$(inputs.threads)`, `$(inputs.files.map(f => f.path).join(' '))`. |
31
+ | `'$(inputs.reads)'` for a data input | A data input is an object, not a path. | `'$(inputs.reads.path)'`. |
32
+ | `container: {type: docker, image: ...}` | `container` is a plain string. | `container: quay.io/biocontainers/...`. |
33
+ | Output written to `'$(inputs.out)'` / a templated output path | UDTs don't pass output paths in; the file is claimed afterward. | Write to a fixed filename, then `from_work_dir: that-file`. |
34
+ | `$(outputs.name.path)` in the command | There is no `outputs` object in the template namespace -- only `inputs`. | Write to a fixed filename and claim it with `from_work_dir`/`discover_datasets`. |
35
+ | `python script.py` with no `configfiles` entry named `script.py` | The file is never created in the working dir, so the command fails at runtime (lint won't catch it). | Add a `configfiles` entry whose `filename` is exactly `script.py`, or inline the code with `python -c`. |
36
+ | Output with neither `from_work_dir` nor `discover_datasets` | `dynamic_tool.output_unclaimed`. | Add one of them. |
37
+ | `$(inputs.foo)` but no input `foo` | `dynamic_tool.undeclared_input_ref`. | Declare `foo` or fix the typo. |
38
+ | `min: 1` / `max: N` on a `data` input | Dropped from the schema in 26.1 (`extra="forbid"` rejects them); authors used `min: 1` to mean "required," but data inputs already are. | Remove them. Data inputs are required by default (`optional: true` to relax); use `multiple: true` to accept several. |
39
+ | `truevalue: --x` / `falsevalue: ""` on a boolean | XML-only fields, rejected. | `value: false` + `$(inputs.x ? '--x' : '')` in the command. |
40
+ | `${on_string}`, `${tool.name}` in labels | Cheetah macros; not supported. | Use a plain string label, or `format_source` to inherit. |
41
+ | `id: My_Tool` / `id: 2pass` | Must be lowercase and start with a letter (`string_pattern_mismatch`). | `id: my-tool`, `id: two-pass`. |
42
+ | Hardcoded `--threads 8` -- even while echoing `$GALAXY_SLOTS` elsewhere | Ignores the job's real allocation; recording the value isn't using it. | Make the flag's value `$GALAXY_SLOTS` (`--threads $GALAXY_SLOTS`) + `resource` `cores_min`. |
43
+ | `container: ubuntu:latest` for a bioinformatics tool | Generic image won't have the binary; not reproducible. | Use the tool's biocontainer. |
44
+ | Invented image/tag/flags | A guessed container or CLI flag fails at runtime. | Use only images/flags you can verify; otherwise ask. |
45
+ | Unescaped literal `$(date)` in the command | Galaxy treats `$(...)` as an expression and errors/misfires. | Escape it: `\$(date)`. |
46
+ | `help` omitted, a bare string, or a `TODO` stub | Galaxy wants `{format, content}`; an empty/missing help leaves a documentation-free black box on the tool page. | Write a real help block: 3 short paragraphs (what / inputs+outputs / caveats). |
47
+ | Free-text scalar inlined unquoted in `shell_command` | `$(inputs.x)` for `text`/`select` interpolates raw (no `shlex.quote`); spaces/quotes break or inject into the command. | Quote it (`'$(inputs.x)'`) or pass free text via a configfile; fixed `select`/numeric values are safe. |
48
+
49
+ ## Verifying a container (the #1 runtime failure)
50
+
51
+ A wrong container is the most common way a UDT passes validation and then fails at run time --
52
+ schema/lint never check that the image exists. Real case: a plotting UDT declared
53
+ `quay.io/biocontainers/seaborn:0.13.2--pyhd8ed1ab_3`, was accepted by `create_user_tool`, and the
54
+ job died with `manifest unknown` because that exact build tag didn't exist on quay.
55
+
56
+ - **Resolve a verified image instead of guessing.** Call `recommend_biocontainer` (Galaxy MCP) with
57
+ the conda packages (`["samtools=1.17", "bwa"]`) and use the `image` it returns, or run
58
+ `mulled-recommend samtools=1.17` in a terminal -- both check quay.io rather than hallucinating.
59
+ - **Never guess the biocontainers build suffix** (`--<hash>_<build>`) -- it isn't derivable from the
60
+ version number. Look it up: browse `https://quay.io/repository/biocontainers/<tool>?tab=tags` or
61
+ query `https://quay.io/api/v1/repository/biocontainers/<tool>/tag/?onlyActiveTags=true`.
62
+ - **Stdlib-only tool? Skip biocontainers.** Use `python:3.x-slim` (or `busybox` for shell-only) and
63
+ write the logic inline -- there's no third-party tag to get wrong. The seaborn failure above was
64
+ fixed precisely this way: switch to `python:3.11-slim` and emit SVG with the standard library.
65
+ - **A clean `validate.py` does not mean the image pulls.** Lint validates the YAML, not the
66
+ registry. Verify the image separately -- `validate.py --check-container`, `recommend_biocontainer`,
67
+ or `mulled-recommend` -- or let the server-create + first run confirm it.
68
+
69
+ ## Clarity pass (what a deterministic validator can't catch)
70
+
71
+ The schema accepts plenty of unhelpful-but-valid tools. Before finishing, also check:
72
+
73
+ - `description` states what the tool does, specifically.
74
+ - Non-obvious inputs have `help` text; `label`s aren't just the parameter name repeated.
75
+ - Common, useful options for the wrapped tool are exposed (e.g. a threads input for an aligner).
76
+ - Defaults are sensible so a user can run it without filling in everything.