Programs

Declare a task

sig = Imp.signature("question -> answer")

sig =
  Imp.signature(
    "ticket -> team: enum[billing,security], urgent: boolean",
    "Route the support ticket."
  )

Run it

program = Imp.predict(sig, lm: lm)
{:ok, prediction} = Imp.call(program, %{ticket: "..."})
Imp.get(prediction, :team)

See what was sent

prediction.metadata.trace.messages

Reason first

Imp.chain_of_thought(sig, lm: lm)

Typed JSON output, with one retry

Imp.predict(sig, lm: lm, adapter: Imp.Adapter.JSON, config: [json_retries: 1])

Models

A provider

lm = Imp.req_llm("openai:gpt-5.4-mini", api_key: System.fetch_env!("OPENAI_API_KEY"))

Swap the model

Imp.with_lm(program, other_lm)

Imp.context([lm: other_lm], fn -> Imp.call(program, inputs) end)

A scripted model for tests

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

Measure

Examples

example =
  Imp.example(ticket: "Charged twice.", team: "billing")
  |> Imp.with_inputs(:ticket)

Evaluate

report = Imp.evaluate(program, devset, Imp.exact_match(:team))
report.score
report.rows

Your own metric

metric = fn example, prediction ->
  Imp.get(prediction, :team) == Imp.get(example, :team)
end

Improve

Add labeled examples (no model calls)

Imp.optimize!(program, Imp.Optimizer.LabeledFewShot.new(k: 8), trainset)

Bootstrap examples the program gets right

Imp.optimize!(program, Imp.Optimizer.BootstrapFewShot.new(metric), trainset)

Search over candidates

optimizer = Imp.Optimizer.BootstrapFewShotWithRandomSearch.new(metric)
Imp.optimize!(program, optimizer, trainset, valset)

Rewrite instructions from feedback

optimizer = Imp.Optimizer.GEPA.new(metric, reflection_lm: strong_lm, max_metric_calls: 400)
Imp.optimize!(program, optimizer, trainset, valset)

Tools and agents

A tool

weather =
  Imp.tool(:weather, "Current weather for a city.", fn %{"city" => city} ->
    Weather.lookup(city)
  end,
    schema: %{
      "type" => "object",
      "properties" => %{"city" => %{"type" => "string"}},
      "required" => ["city"]
    }
  )

An agent loop

agent = Imp.react("question -> answer", [weather], lm: lm, max_iters: 5)
{:ok, prediction} = Imp.call(agent, %{question: "Is it raining in Lisbon?"})

# Each step's tool calls and their results.
prediction.metadata.history.messages

Tools from MCP servers

server = %{"name" => "docs", "type" => "http", "url" => "https://example.com/mcp"}
{:ok, imported} = Imp.MCP.connect([server], trusted_servers: [server])
agent = Imp.react("question -> answer", imported.tools, lm: lm)
imported.cleanup.()

Keep and inspect

Save and load (no credentials saved)

:ok = Imp.save!(program, "router.json")
program = "router.json" |> Imp.read!() |> Imp.with_lm(lm)

Capture telemetry around a call

trace = Imp.trace(fn -> Imp.call(program, inputs) end)
trace.events