Declarative self-improving language-model programs for Elixir.

Imp programs are ordinary Elixir structs with explicit signatures, injectable model clients, measurable behavior, and optimizer-driven improvement loops.

Most application code should start here. The deeper Imp.* modules are available when you need direct control, but the facade gives the normal flow: configure an LM, declare a signature, build a program, call it, evaluate it, and improve it.

A tiny deterministic program

lm = Imp.LM.Static.new(handler: fn _messages, _opts -> %{answer: "Paris"} end)

Imp.configure(lm: lm, adapter: Imp.Adapter.Chat)

program =
  "question -> answer: short_span"
  |> Imp.signature("Answer with the shortest correct span.")
  |> Imp.predict()

{:ok, prediction} =
  Imp.call(program, %{question: "What city is the Eiffel Tower in?"})

Imp.get(prediction, :answer)

Production provider boundary

Swap the LM dependency without changing the task:

lm =
  Imp.req_llm("openai:" <> System.fetch_env!("OPENAI_MODEL"),
    api_key: System.fetch_env!("OPENAI_API_KEY"),
    temperature: 0
  )

Imp.configure(lm: lm, adapter: Imp.Adapter.Chat)

Imp owns the programming layer: signatures, adapters, examples, metrics, optimizers, traces, persistence, and telemetry. Provider transport and model details belong to ReqLLM.

Summary

Functions

Appends a signature-shaped turn to conversation history.

Wraps a program with assertion-guided self-refinement.

Builds a named runtime assertion for assertion-guided refinement.

Creates a bounded action-history Avatar actor with a reserved Finish action.

Creates a wrapper that runs a program repeatedly and keeps the best scored prediction.

Wraps an LM with prospective request/token/USD admission.

Calls any Imp program struct.

Cooperatively cancels an addressable program run and its supervised task.

Creates a program that asks for reasoning before final outputs.

Returns a structured classification metric result for one prediction/label pair.

Summarizes classification rows into precision, recall, F1, and accuracy.

Creates a CodeAct-style module backed by the BEAM-safe sandbox.

Streams one program call and joins the chunks into a string.

Configures global settings such as :lm and :adapter.

Runs fun with temporary process-local settings.

Disables Imp-scoped logging.

Returns a JSON-safe portable representation of an Imp program.

Enables Imp-scoped logging.

Evaluates a program against examples with a metric.

Builds a metric that compares one prediction field to the same example field.

Builds a train/dev/test example row.

Returns a structured extractive-QA metric result for one prediction/answer pair.

Reads a field from a prediction or example.

Builds signature-shaped conversation history for history-aware programs.

Returns the input fields for an example.

Renders recent history turns with secret redaction enabled by default.

Builds a callable embedding-based KNN predictor over an example trainset (DSPy KNN port). Requires :vectorizer — an Imp.Embeddings provider.

Returns the label/output fields for an example.

Loads a program from the portable map dump/1 returns.

Loads a program from the portable map dump/1 returns, raising on failure.

Returns the majority value across predictions.

Builds a deterministic in-memory retriever for local RAG workflows.

Creates a self-consistency comparison program over candidate completions.

Retrieves nearest examples from an Imp KNN predictor for one input map.

Compiles a program with an optimizer.

Compiles a program with an optimizer, raising on failure.

Returns the explicit execution capabilities declared by an optimizer.

Runs heterogeneous {program, inputs} pairs through one supervised task pool.

Runs one program over a batch of inputs through Imp's supervised task boundary.

Creates a basic signature-to-prediction program.

Builds a structured prediction.

Creates a program-of-thought module backed by the BEAM-safe sandbox.

Wraps a program with retrieval-augmented context injection.

Creates a tool-using agent: an Imp.Predict.ReActV2 program.

Reads a program artifact save!/2 wrote to disk; see Imp.Saving.read!/2.

Creates a wrapper that retries a program with feedback until a metric passes.

Creates a ReqLLM-backed multi-provider LM client.

Calls any Imp retriever and normalizes returned documents.

Creates a recursive controller loop for large-context exploration.

Creates a lazy RLM input that can be loaded with a controller load action.

Writes an Imp program artifact to disk as JSON.

Returns the effective settings for the current process.

Builds a declarative input/output contract.

Starts a prospective request, token, and USD ledger for live optimization.

Starts an addressable program run with ordered semantic events and cancellation.

Streams one program call as an Enumerable of chunks.

Subscribes the current process to normalized optimizer progress events.

Converts a prediction or example to its field map.

Creates a named tool for ReAct programs and agents.

Runs a function while collecting selected redacted Imp telemetry events.

Executes a training optimizer through the explicit training lifecycle.

Detaches an optimizer progress subscription.

Attaches demonstrations to a demo-bearing Imp program or example.

Marks which fields of an example are inputs.

Returns a copy of an Imp program pinned to lm.

Executes a program with immutable active playbook guidance.

Functions

append_history(history, turn)

Appends a signature-shaped turn to conversation history.

assert(program, assertions, opts \\ [])

Wraps a program with assertion-guided self-refinement.

assertion(name, predicate, opts \\ [])

Builds a named runtime assertion for assertion-guided refinement.

avatar(signature, tools, opts \\ [])

Creates a bounded action-history Avatar actor with a reserved Finish action.

best_of_n(program, metric, opts \\ [])

Creates a wrapper that runs a program repeatedly and keeps the best scored prediction.

budgeted_lm(lm, budget, opts \\ [])

Wraps an LM with prospective request/token/USD admission.

The wrapper caps output, disables cache and hidden retries, and rejects calls before transport when their worst-case reservation would exceed the ledger.

call(program, inputs)

Calls any Imp program struct.

cancel_run(run, reason \\ :cancelled, timeout \\ 5000)

Cooperatively cancels an addressable program run and its supervised task.

chain_of_thought(signature, opts \\ [])

Creates a program that asks for reasoning before final outputs.

classification(prediction, label, opts \\ [])

Returns a structured classification metric result for one prediction/label pair.

classification_report(rows, opts \\ [])

Summarizes classification rows into precision, recall, F1, and accuracy.

code_act(signature, tools \\ [], opts \\ [])

Creates a CodeAct-style module backed by the BEAM-safe sandbox.

collect(program, inputs, opts \\ [])

Streams one program call and joins the chunks into a string.

If any chunk fails, collection stops and returns {:error, reason} rather than partial output.

configure(opts)

Configures global settings such as :lm and :adapter.

Prefer passing explicit dependencies to individual programs when a program must be self-contained. Use configure/1 for application defaults and context/2 for request-scoped overrides.

context(opts, fun)

Runs fun with temporary process-local settings.

This is the preferred way to override the LM or adapter for one request, test, task, or Livebook cell without mutating global defaults. Keys of the caller's own, such as a request id, are carried too; Imp's own settings are type-checked as in configure/1. See Imp.Settings.context/2.

disable_logging()

Disables Imp-scoped logging.

dump(program)

Returns a JSON-safe portable representation of an Imp program.

dump(program, opts)

See Imp.Saving.dump/2.

enable_logging()

Enables Imp-scoped logging.

evaluate(program, devset, metric, opts \\ [])

Evaluates a program against examples with a metric.

This is the facade form of:

devset
|> Imp.Evaluate.new(metric, opts)
|> Imp.Evaluate.run(program)

exact_match(field \\ :answer)

Builds a metric that compares one prediction field to the same example field.

example(fields)

Builds a train/dev/test example row.

extractive_qa(prediction, answer, opts \\ [])

Returns a structured extractive-QA metric result for one prediction/answer pair.

get(container, key, default \\ nil)

Reads a field from a prediction or example.

history(messages \\ [])

Builds signature-shaped conversation history for history-aware programs.

inputs(example)

Returns the input fields for an example.

inspect_history(history, opts \\ [])

Renders recent history turns with secret redaction enabled by default.

knn(k, trainset, opts \\ [])

Builds a callable embedding-based KNN predictor over an example trainset (DSPy KNN port). Requires :vectorizer — an Imp.Embeddings provider.

labels(example)

Returns the label/output fields for an example.

load(state, opts \\ [])

Loads a program from the portable map dump/1 returns.

Returns {:ok, program} or {:error, %ArgumentError{}}; see Imp.Saving.load/2.

load!(state, opts \\ [])

Loads a program from the portable map dump/1 returns, raising on failure.

majority(predictions, opts \\ [])

Returns the majority value across predictions.

memory(docs, opts \\ [])

Builds a deterministic in-memory retriever for local RAG workflows.

multi_chain_comparison(signature, opts \\ [])

Creates a self-consistency comparison program over candidate completions.

nearest(knn, inputs)

Retrieves nearest examples from an Imp KNN predictor for one input map.

optimize(program, optimizer, trainset)

Compiles a program with an optimizer.

Returns {:ok, compiled_program} or {:error, reason}, mirroring Imp.train/4. Use Imp.optimize!/3 when you want the compiled program directly and a raise on failure.

Optimizer modules declare their dataset requirements through the Imp.Optimizer behaviour. Use Imp.optimize/4 for optimizers that need a validation set and Imp.optimize/3 for trainset-only optimizers. A non-empty keyword list in the fourth position supplies invocation options to a trainset-only optimizer; invocation options alongside a validation set belong in Imp.optimize/5. Operational route, cost, budget, transport, and explicit cancellation guards remain raised even through this non-bang facade; they are not ordinary candidate failures.

optimize(program, optimizer, trainset, validation_or_opts)

optimize(program, optimizer, trainset, validation, opts)

optimize!(program, optimizer, trainset)

Compiles a program with an optimizer, raising on failure.

Same contract as optimize/3, optimize/4, and optimize/5, but returns the compiled program directly. A call that could never run (not an optimizer, a training optimizer, a missing validation set, options the optimizer refused) raises ArgumentError; an optimization that failed raises Imp.Error whose :reason is the term optimize would have returned.

optimize!(program, optimizer, trainset, validation_or_opts)

optimize!(program, optimizer, trainset, validation, opts)

optimizer_capabilities(optimizer)

Returns the explicit execution capabilities declared by an optimizer.

parallel(exec_pairs)

Runs heterogeneous {program, inputs} pairs through one supervised task pool.

parallel(exec_pairs, opts)

Runs one program over a batch of inputs through Imp's supervised task boundary.

parallel(program, inputs, opts)

predict(signature, opts \\ [])

Creates a basic signature-to-prediction program.

Predict is the first program shape to reach for: one call maps named inputs to named outputs. Add demos, metrics, and optimizers before reaching for agents or recursive controllers.

prediction(fields)

Builds a structured prediction.

program_of_thought(signature, opts \\ [])

Creates a program-of-thought module backed by the BEAM-safe sandbox.

rag(program, retriever, opts \\ [])

Wraps a program with retrieval-augmented context injection.

react(signature, tools, opts \\ [])

Creates a tool-using agent: an Imp.Predict.ReActV2 program.

The model calls tools natively, one step per request, and the turn ends when it answers in text or, for a signature a text answer cannot fill, calls submit. See Imp.Predict.ReActV2.new/3 for the options. Imp.Predict.ReAct is the earlier loop, kept for its byte-faithful mode: :dspy port of DSPy's dspy.ReAct.

read!(path, opts \\ [])

Reads a program artifact save!/2 wrote to disk; see Imp.Saving.read!/2.

refine(program, metric, opts \\ [])

Creates a wrapper that retries a program with feedback until a metric passes.

req_llm(model_spec, opts \\ [])

Creates a ReqLLM-backed multi-provider LM client.

retrieve(retriever, query, opts \\ [])

Calls any Imp retriever and normalizes returned documents.

rlm(signature, opts \\ [])

Creates a recursive controller loop for large-context exploration.

rlm_serializable(name, loader, opts \\ [])

Creates a lazy RLM input that can be loaded with a controller load action.

save!(program, path)

Writes an Imp program artifact to disk as JSON.

save!(program, path, opts)

See Imp.Saving.save!/3.

settings()

Returns the effective settings for the current process.

signature(spec, instructions \\ nil)

Builds a declarative input/output contract.

Imp.signature("question -> answer: short_span")

Signatures may also be maps when you need explicit constraints.

start_optimizer_budget(opts)

Starts a prospective request, token, and USD ledger for live optimization.

Supply :limits, :pricing, and :default_max_output_tokens. A prior Imp.Optimizer.Budget.snapshot/1 may be passed as :initial; unresolved reservations are then conservatively charged once instead of restoring spend capacity after a crash.

Wrap every task and proposal LM with budgeted_lm/3; the wrapper records ReqLLM provider usage for each call and releases its reservation afterward.

start_run(program, inputs, opts \\ [])

Starts an addressable program run with ordered semantic events and cancellation.

Pass authorize: fun to require a protocol-neutral decision before each validated external ReActV2 or RLM tool effect. The function receives an Imp.Execution.Authorization and must return :allow, {:deny, reason}, or {:cancel, reason}. A crash, timeout, malformed response, or vanished run owner denies the effect. Programs that do not support explicit execution capabilities fail closed when :authorize is present.

event_sink: fun receives redacted events serially from a run-owned delivery process. A slow sink delays its own later events and delivery barriers, but it cannot delay cancel_run/3 or owner-death cleanup. Event sinks should normally forward events to their host mailbox and return promptly.

Pass admission: {pool, limit} to count the run in a pool the host names, with its own limit; a full pool returns {:error, :busy} at once. Pass deadline: ms to bound the run with Imp.Deadline; without it the run inherits the caller's deadline. When the deadline passes while the run waits for a place in the pool, it returns {:error, :deadline_exceeded} and starts nothing. See Imp.Run.start/3.

stream(program, inputs, opts \\ [])

Streams one program call as an Enumerable of chunks.

Pass provider_stream: true to execute the real program while yielding provider chunks from its named predictors. Supply stream_listeners: to select fields from intermediate predictors. A final typed Imp.Prediction is yielded by default after the composed program finishes. Without provider streaming, the program runs once and its result is chunked locally.

subscribe_optimizer_progress(opts \\ [])

Subscribes the current process to normalized optimizer progress events.

to_map(container)

Converts a prediction or example to its field map.

Keys keep the type of the signature's field names. Names written in the string syntax are atoms only if that atom already exists, otherwise strings, so read values with Imp.get/2, which matches either spelling.

tool(name, description, run, opts \\ [])

Creates a named tool for ReAct programs and agents.

The function receives one map with string keys, the shape a JSON tool call carries, whichever runtime calls it:

Imp.tool(:lookup, "look up a fact", fn %{"query" => query} -> query end)

Keys are never atoms, so match on strings. See Imp.Tool.

trace(fun, opts \\ [])

Runs a function while collecting selected redacted Imp telemetry events.

train(program, optimizer, trainset, opts \\ [])

Executes a training optimizer through the explicit training lifecycle.

The result is tagged and contains a Imp.Optimizer.TrainingResult. SFT returns status: :job_created; synchronous reinforcement training returns status: :completed with the rebound program. When a training optimizer owns multiple independent provider jobs, TrainingResult.jobs is exhaustive and the singular TrainingResult.job is nil.

unsubscribe_optimizer_progress(subscription)

Detaches an optimizer progress subscription.

with_demos(program_or_example, demos)

Attaches demonstrations to a demo-bearing Imp program or example.

with_inputs(example, keys)

Marks which fields of an example are inputs.

with_lm(program, lm)

Returns a copy of an Imp program pinned to lm.

This is the public rebinding path for programs loaded from portable artifacts. Saved provider programs retain non-secret provider configuration, but never credentials, so bind a newly configured LM before calling them:

loaded
|> Imp.with_lm(Imp.req_llm(System.fetch_env!("IMP_MODEL"), api_key: api_key))
|> Imp.call(%{question: "What changed?"})

Core predictors, callback wrappers, evaluators, and optimizer-produced KNN few-shot and ensemble graphs are supported. Rebinding traverses the complete executable graph and pins every nested predictor to the supplied LM.

with_playbook(program, playbook)

Executes a program with immutable active playbook guidance.