Oi

Oi means Orchid integration — lightweight glue layer between Orchid workflows and OrchidSymbiont runtimes.

Core concepts

Quick start

Same example with orchid.

Define a step

defmodule Barista.Grind do
use Oi.Step, name: :grind
manifest(inputs: [:beans], outputs: [powder: :solid])
routine beans_amount, opts do
IO.puts("⚙️ Grinding #{beans_amount}g beans...")
beans_amount * Keyword.get(opts, :ratio, 1) |> ok()
end
end
defmodule Barista.Brew do
use Oi.Step, name: :brew
manifest(inputs: [:powder, :water], outputs: [coffee: :liquid])
routine [powder_amount, water_amount], opts do
style = Keyword.get(opts, :style, :espresso)
IO.puts("💧 Brewing #{style} coffee with #{powder_amount}g powder and #{water_amount}ml water...")
ok("Cup of #{style}")
end
end

Build and run

import Oi.Flowgraph
graph =
new_flowchart()
|> add_step(Barista.Grind)
|> add_step(Barista.Brew, opts: [style: :latte])
|> connect({:grind, :powder}, {:brew, :powder})
{:ok, compiled} = Oi.compile(graph)
{:ok, result} = Oi.execute(compiled,
data: %{grind: %{beans: 20}, brew: %{water: 200}}
)
{:ok, coffee} = Oi.Result.reify(result, {:brew, :coffee})
IO.inspect(coffee)
# => "Cup of latte"

With interventions

# Override an intermediate port — wrap the value with intervention type
{:ok, result} = Oi.execute(compiled,
data: %{
step1: %{in: "hello"},
step2: %{in: {:override, "forced_value"}} # step2.in has upstream edge → intervention
},
orchid_opts: [
global_hooks_stack: [Orchid.Hook.ApplyInterventions]
]
)

Multi-tenant with Session

Oi.Runtime.Session.start("tenant-1")
graph = build_graph()
{:ok, compiled} = Oi.compile(graph)
{:ok, result} = Oi.execute(compiled,
data: %{step: %{in: "data"}},
executor: Oi.Executor.TaskSup,
executor_opts: [sup: Oi.Runtime.Session.tasks_tuple("tenant-1")],
orchid_baggage: %{scope_id: "tenant-1"},
orchid_opts: [global_hooks_stack: [OrchidSymbiont.Hooks.Injector]]
)
Oi.Runtime.Session.stop("tenant-1")

Symbiont step

defmodule MyApp.Steps.Predict do
use Oi.Step, name: :predict, symbiont?: true
manifest(
inputs: [:features],
outputs: [prediction: :string],
models: [:model]
)
routine features, models, _opts do
{:ok, result} = OrchidSymbiont.call(models.model, {:predict, features})
ok(result)
end
end

Roadmap

License

MIT