Tool Authoring¶
A tool plugin should provide a narrow integration layer around scientific workflow logic.
Distribution dependencies¶
Declare caddforge-core>=0.21.0 in plugin project.dependencies; do not depend on
caddforge, which is the complete toolbox bundle. Keep Python imports and entry-point
groups under caddforge. Adding a public plugin to the bundle requires an explicit,
exact dependency pin and a newly tested bundle release. Only reviewed public components belong in the public bundle.
Optional CLI commands¶
An installed package can add a top-level CLI command through the caddforge.cli_commands
entry-point group. Core 0.21.0 introduces this interface. The entry-point name becomes the command
name; its target is a callable with a Typer-compatible signature and help docstring:
Core registers these commands after its built-in commands and groups. Conflicts, duplicate command
names, and extensions that fail to load or have unsupported signatures are logged and skipped,
leaving built-in commands available. Keep extension imports lightweight and load expensive runtime
dependencies only when the command executes. Removing the providing package removes its command
from subsequent CLI invocations. Plugins that only expose scientific tools should continue to use
the caddforge.tools group.
Required pieces¶
- Config model with validation and YAML/JSON loading support.
- Workflow class that prepares and runs jobs.
- Tool metadata class registered through
caddforge.toolsentry points. - Canonical
Resultoutput with metrics and paths. - Tests for config validation, workflow setup, and result generation.
Pipeline contracts¶
Expose pipeline ports when a tool should participate in pipelines:
InputPort(name="ligands", kind=ArtifactKind.MOLECULE_COLLECTION, config_field="ligand_paths")
OutputPort(name="scores", kind=ArtifactKind.TABULAR_SCORES, result_path_key="best_scores_csv")
OutputPort(
name="pose_files",
kind=ArtifactKind.POSE_COLLECTION,
result_path_key="pose_manifest_csv",
required=False,
path_collection_column="pose_file",
)
Use declared ports or explicit outputs mappings. Do not force downstream stages to infer paths
from tool-specific output directories.
Runtime input and compression contracts¶
Set InputPort.config_field to the configuration path that receives a pipeline artifact. Core also
uses declared inputs to materialize transparent gzip wrappers immediately before execution. For a
nested collection, set runtime_selector, for example input_files[].path. Mark a selector with
InputCompressionPolicy.NATIVE when the scientific tool consumes the compressed stream itself.
Outputs requested with a .gz suffix require an OutputPort.config_field so core can distinguish
the requested destination from an existing compressed input and finalize it atomically.
Structured collection fields can declare a SplitContract that identifies the path member to
split, preserves sibling metadata in every shard, and selects a deterministic reducer for shard
outputs.
Scratch publication helpers¶
Use LogSync for mutable stdout, stderr, or progress snapshots written in scratch. Set
atomic=True for structured snapshots and inspect its LogSyncReport when the final publication
state belongs in the result. Synchronization failures are retried and must not change scientific
job status.
Use ArtifactSyncQueue for completed immutable artifacts. It publishes by atomic replacement,
retries transient failures, and reports unresolved files after the final pass. Do not place
tool-specific behavior in these core helpers.
Backends¶
Workflow code should not contain Slurm-specific or local-process orchestration. Submit and track jobs through the core backend interfaces.