Behavior for pipeline steps with strongly-typed inputs and outputs.
Each step declares its input/output types and produces artifacts. Steps are the atomic units of work in the scraping pipeline.
Input/Output Schemas
Input and output schemas are plain Elixir structs with typespecs.
Use @enforce_keys for required fields and @derive Jason.Encoder
for output schemas that need JSON serialization.
Example Implementation
defmodule MyStep do
@behaviour ALLM.Pipeline.Step
defmodule Input do
@enforce_keys [:url]
defstruct [:url]
@type t :: %__MODULE__{url: String.t()}
end
defmodule Output do
@derive Jason.Encoder
@enforce_keys [:result]
defstruct [:result]
@type t :: %__MODULE__{result: String.t()}
end
@impl true
def step_type, do: :my_step
@impl true
def input_schema, do: __MODULE__.Input
@impl true
def output_schema, do: __MODULE__.Output
@impl true
def execute(_context, %Input{} = input) do
# Process input and return output
{:ok, %Output{result: "processed"}}
end
# Optional: Store artifacts
@impl true
def artifact_content_type, do: "text/html"
@impl true
def artifact_content(%Output{html: html}), do: html
end
Summary
Types
What a step receives as its first argument: an ALLM.Pipeline.Context struct.
Callbacks
Optional: extract artifact content from output for storage
Optional: artifact content type for storage (e.g., 'text/html', 'application/json')
Execute the step with validated input, return validated output
The struct module for input (plain Elixir struct with typespecs)
The struct module for output (plain Elixir struct with typespecs)
The step type identifier (e.g., :scrape_committee_list)
Functions
Check if a module implements the Step behavior.
Check if a step module produces artifacts.
Types
@type context() :: ALLM.Pipeline.Context.t()
What a step receives as its first argument: an ALLM.Pipeline.Context struct.
Widened from a bare map in Phase 4 (D5). It always WAS that struct —
ALLM.Pipeline.Executor.run_with_step_log/5 has only ever built one — but the
type said %{pipeline_run: …, step_log: …}, which is both weaker and, since
step_log became nilable for escape-hatch bodies, wrong. A struct is a map,
so this narrows nothing at runtime and is dialyzer-visible only.
Callbacks
Optional: extract artifact content from output for storage
@callback artifact_content_type() :: String.t()
Optional: artifact content type for storage (e.g., 'text/html', 'application/json')
@callback execute(context(), input :: struct()) :: execute_result()
Execute the step with validated input, return validated output
@callback input_schema() :: module()
The struct module for input (plain Elixir struct with typespecs)
@callback output_schema() :: module()
The struct module for output (plain Elixir struct with typespecs)
@callback step_type() :: atom()
The step type identifier (e.g., :scrape_committee_list)