Jidoka: Characters And Instructions
Characters provide structured persona and voice. Instructions still define the task. Jidoka renders the character before instructions in the effective system prompt.
Setup
Mix.install(
[
{:jidoka, git: "https://github.com/mikehostetler/jidoka.git", ref: "924a486f3c1b7e7a943cb3d5ceee0de65f158467"},
{:kino, "~> 0.19.0"}
],
config: [
jidoka: [
model_aliases: %{fast: "anthropic:claude-haiku-4-5"}
]
]
)
Jidoka.Kino.setup()
Define Characters
defmodule LivebookDemo.Characters.SupportAdvisor do
use Jido.Character,
defaults: %{
name: "Support Advisor",
identity: %{role: "Support specialist"},
voice: %{tone: :professional, style: "Clear and concise"},
instructions: ["Use the configured support persona."]
}
end
defmodule LivebookDemo.Characters.Agent do
use Jidoka.Agent
agent do
id :livebook_character_agent
end
defaults do
model :fast
character LivebookDemo.Characters.SupportAdvisor
instructions "Adapt the answer to the account tier."
end
end
%{
configured_character: LivebookDemo.Characters.Agent.character(),
instructions: LivebookDemo.Characters.Agent.instructions()
}
Inspect The Effective Prompt
request = %{messages: [%{role: :user, content: "hello"}], llm_opts: [], tools: %{}}
state = Jido.AI.Reasoning.ReAct.State.new("hello", nil, request_id: "req-character", run_id: "run-character")
config =
Jido.AI.Reasoning.ReAct.Config.new(
model: :fast,
system_prompt: nil,
request_transformer: LivebookDemo.Characters.Agent.request_transformer(),
streaming: false
)
{:ok, %{messages: [%{role: :system, content: prompt}, %{role: :user, content: "hello"}]}} =
LivebookDemo.Characters.Agent.request_transformer().transform_request(request, state, config, %{})
prompt
Override Character Per Turn
Runtime character overrides are explicit chat/3 options, so applications can
choose when a persona changes.
{:ok, opts} =
Jidoka.Agent.prepare_chat_opts(
[
character: %{
name: "Runtime Advisor",
voice: %{tone: :warm},
instructions: ["Use the runtime persona for this turn only."]
}
],
%{context: %{}, context_schema: nil}
)
runtime_context = Keyword.fetch!(opts, :tool_context)
{:ok, %{messages: [%{role: :system, content: runtime_prompt}, _user]}} =
LivebookDemo.Characters.Agent.request_transformer().transform_request(
request,
state,
config,
runtime_context
)
runtime_prompt
Optional Provider Turn
{:ok, pid} =
Jidoka.Kino.start_or_reuse("livebook-character-agent", fn ->
LivebookDemo.Characters.Agent.start_link(id: "livebook-character-agent")
end)
Jidoka.Kino.chat("Character chat", fn ->
LivebookDemo.Characters.Agent.chat(pid, "Explain the value of character prompts in one sentence.")
end)