Jidoka 01 · Your First Agent
# Pin Jidoka to a specific Git revision so this notebook resolves the same
# code every time. After Jidoka ships on Hex you can swap this for the
# commented Hex line below.
jidoka_dep = {:jidoka, github: "agentjido/jidoka", ref: "729afdc"}
# jidoka_dep = {:jidoka, "~> 1.0"}
Mix.install(
[
jidoka_dep,
{:kino, "~> 0.13"}
],
config: [
jidoka: [
# `:fast` is the shared example alias used across Jidoka notebooks.
# Define it once here and every cell can write `model :fast`.
model_aliases: %{
fast: "anthropic:claude-haiku-4-5"
}
]
],
consolidate_protocols: false
)
What You Will Learn
This is the first notebook in the Jidoka teaching track and the template every later notebook follows. By the end you will have:
- defined an agent with the compile-time DSL,
- started a conversation with a stable session,
- run a turn without needing a model key, and
-
used the built-in
Jidoka.Kinohelpers to inspect and debug what happened.
Three concepts to internalize:
- Agent — a compiled module describing identity, model, and instructions.
-
Session — the conversation address that carries runtime
context. -
Turn — one call to
Jidoka.chat/3, traceable end-to-end.
> 💡 Every cell in this notebook is safe to re-evaluate. The provider-free > sections work without any API key. The optional live cell at the end only > runs if an Anthropic key is available.
Setup · Install Jidoka And A Provider Key
The Mix.install/2 cell at the top installs Jidoka from GitHub (until it
ships on Hex) and registers the :fast model alias so the rest of the
notebook can write model :fast instead of a full provider string.
Adding your Anthropic key (optional)
To run the optional live cell at the end, give the notebook access to an Anthropic key in one of two ways:
-
Livebook Secret (recommended).
In the left sidebar click the 🔒 Secrets icon and add a secret named
ANTHROPIC_API_KEYwith yoursk-ant-…value. Then click Toggle next to it for this notebook session. Livebook will expose it as the env variableLB_ANTHROPIC_API_KEYand the setup helper copies it intoANTHROPIC_API_KEYautomatically. -
Shell env. Set
ANTHROPIC_API_KEY=sk-ant-…before launching Livebook.
If neither is set, the notebook still teaches the concept — it just skips the single live cell.
Calling the setup helper
Jidoka.Kino.setup_notebook/1 does four small things so notebook cells stay
focused on the agent code:
-
quiets Jidoka’s raw runtime logs (use
show_raw_logs: trueto flip back on), -
bridges Livebook’s
LB_ANTHROPIC_API_KEYsecret intoANTHROPIC_API_KEY, - renders a compact setup table so you can see provider/model status, and
-
returns a summary map with a
:live_provider?flag you can branch on.
setup = Jidoka.Kino.setup_notebook(provider: :anthropic)
# Bind the provider-ready flag so later cells can decide whether to skip.
live_provider? = setup.live_provider?
Define Your First Agent
A Jidoka agent is just a module that uses the DSL. The minimum useful agent needs three things:
-
a stable id (
:first_agent) — Jidoka uses it to name runtime processes, sessions, and trace events, -
a model —
:fastresolves through the alias registered in setup, and - instructions — the system prompt the model sees.
defmodule Demo.Assistant do
use Jidoka.Agent
agent :first_agent do
model :fast
instructions "Answer clearly and concisely."
end
end
That module now has accessor functions for every part of the declared shape. The next cell shows the most useful ones at a glance.
%{
id: Demo.Assistant.id(),
model: Demo.Assistant.configured_model(),
instructions: Demo.Assistant.instructions(),
runtime_module: Demo.Assistant.runtime_module()
}
Inspect the compiled surface with Kino
Jidoka.Kino.debug_agent/1 renders the same information as three small
Kino tables: identity, capabilities, and lifecycle. This is the recommended
view for “what did the DSL actually produce?”.
{:ok, _inspection} = Jidoka.Kino.debug_agent(Demo.Assistant)
Visualize it as a Mermaid diagram
agent_diagram/1 renders a flowchart of the agent’s model, context,
lifecycle, and tools. Even on a tiny agent it’s a useful sanity check —
once you start adding tools, workflows, and subagents you’ll see them
appear here.
{:ok, _markdown} = Jidoka.Kino.agent_diagram(Demo.Assistant)
Start A Conversation With A Session
A Jidoka.Session is data, not a process. It pins:
-
an
agent_id— which agent should handle the turn, -
a
conversation_id— a stable name for this thread of messages, and -
a
contextmap — caller-supplied runtime facts (actor id, tenant id, ticket id, …) that flow into prompts, tools, controls, and traces.
session =
Demo.Assistant
|> Jidoka.session("user-123", context: %{actor_id: "user_123", tenant: "demo"})
%{
session_id: session.id,
agent_id: session.agent_id,
conversation_id: session.conversation_id
}
Inspect the context the agent will see
Jidoka.Kino.context/2 separates public application keys from Jidoka’s
internal bookkeeping so you can spot at a glance what the model and tools
actually get.
Jidoka.Kino.context("Session context", session.context)
Run A Provider-Free Turn
You can prove the full chat pipeline runs — start the runtime, merge
context, create a request, record trace events — without spending a
single token. The trick is an input control that interrupts before the
provider call. Jidoka returns an {:interrupt, …} result that contains the
exact request the model would have been called with.
stop_before_provider = fn input ->
Jidoka.Approval.request("Stop before provider execution.",
data: %{
request_id: input.request_id,
context: Jidoka.Context.strip_internal(input.context)
}
)
end
{:interrupt, interrupt} =
Jidoka.chat(session, "In one sentence, explain what a Jidoka session is.",
controls: [input: stop_before_provider]
)
%{
kind: interrupt.kind,
message: interrupt.message,
request_id: interrupt.data.request_id,
context_seen_by_control: interrupt.data.context
}
Debug The Turn
The same session is the address for every debugging helper. After any turn (even an interrupted one), you can inspect:
- the request — what would have been sent to the model,
- the trace — ordered events showing what ran when, and
- the call graph — a Mermaid view of capability calls.
{:ok, _request} = Jidoka.Kino.debug_request(session)
The trace helpers look traces up by agent — pass session.agent_id (or a
running pid, or a Jidoka.Trace struct):
{:ok, _trace} = Jidoka.Kino.timeline(session.agent_id)
{:ok, _graph} = Jidoka.Kino.call_graph(session.agent_id)
> ℹ️ Use Jidoka.Kino.trace_table/1 when you want the raw structured
> events with their metadata instead of the compact timeline view.
Optional · A Live Provider Turn
If the setup table showed Anthropic as ready, the cell below will make a real one-shot call. Otherwise it skips cleanly so this notebook stays runnable end-to-end without credentials.
Jidoka.Kino.chat/2 wraps Jidoka.chat/3: it captures runtime log events,
extracts the plain text reply, and renders a small result table.
if live_provider? do
live_session =
Demo.Assistant
|> Jidoka.session("live-user", context: %{actor_id: "user_123"})
Jidoka.Kino.chat("first live turn", fn ->
Jidoka.chat(live_session, "In one sentence, what is a Jidoka session?")
end)
else
{:skipped, "Add an ANTHROPIC_API_KEY (env or Livebook secret) to run this cell."}
end
What Jidoka Owned · What You Still Own
Jidoka owned the agent DSL, the session address, the turn lifecycle, and the debugging projection. Your application is still responsible for:
-
the real
actor_id/tenant/ business ids you pass into context, - provider credentials and how they reach the Livebook or runtime,
- supervision when you graduate the agent into a long-running app, and
- durable storage if conversations must survive process restarts.
Next
Continue with the broader walkthrough in
getting_started.livemd, which builds on this
same template to cover typed results, actions, controls, workflows,
schedules, and delegation.