# Quick Start

[![Run in Livebook](https://livebook.dev/badge/v1/blue.svg)](https://livebook.dev/run?url=https://github.com/agentjido/jido/blob/main/guides/getting-started.livemd)

```elixir
Mix.install([
  {:jido, "~> 2.0"}
])
```

## Overview

This guide gets you from zero to a working Jido agent in 5 minutes. You'll learn:

1. How to start Jido's supervision tree
2. How to define an agent with state
3. How to use `cmd/2` for pure state transformations
4. How to run agents in AgentServer for real applications

## Step 1: Start Jido

Jido uses instance-scoped supervisors. Define an instance module and add it to your supervision tree:

```elixir
# In lib/my_app/jido.ex
defmodule MyApp.Jido do
  use Jido, otp_app: :my_app
end
```

```elixir
# In config/config.exs
config :my_app, MyApp.Jido,
  max_tasks: 1000,
  agent_pools: []
```

```elixir
# In your application.ex
children = [
  MyApp.Jido
]

Supervisor.start_link(children, strategy: :one_for_one)
```

For this Livebook, we'll start it directly:

```elixir
defmodule Demo.Jido do
  use Jido, otp_app: :demo
end

{:ok, _pid} = Demo.Jido.start_link()
```

## Step 2: Define an Agent

Agents are immutable structs with a schema defining their state:

```elixir
defmodule CounterAgent do
  use Jido.Agent,
    name: "counter",
    description: "A simple counter agent",
    schema: [
      count: [type: :integer, default: 0],
      status: [type: :atom, default: :idle]
    ]
end
```

## Step 3: Use cmd/2 for State Transformations

The core pattern in Jido is `cmd/2`: pass an agent and an action, then receive
the updated agent and any directives for runtime-owned effects:

```elixir
{agent, directives} = MyAgent.cmd(agent, action)
```

Let's define an action and use it:

```elixir
defmodule IncrementAction do
  use Jido.Action,
    name: "increment",
    description: "Increments the counter by a given amount",
    schema: [
      amount: [type: :integer, default: 1]
    ]

  @impl true
  def run(params, context) do
    current = context.state[:count] || 0
    {:ok, %{count: current + params.amount}}
  end
end
```

Now use it:

```elixir
agent = CounterAgent.new()
IO.inspect(agent.state, label: "Initial state")

{agent, _directives} = CounterAgent.cmd(agent, {IncrementAction, %{amount: 5}})
IO.inspect(agent.state, label: "After increment by 5")

{agent, _directives} = CounterAgent.cmd(agent, IncrementAction)
IO.inspect(agent.state, label: "After increment by 1")
```

Key points:
- The returned agent is fully updated
- Actions may be pure or effectful when they need a result back now
- Directives describe runtime-owned effects and never modify state

## Step 4: Handle Signals with AgentServer

For real applications, agents run inside AgentServer - a GenServer that handles signals and executes directives.

First, let's add signal handling to our agent:

```elixir
defmodule CounterAgentWithSignals do
  use Jido.Agent,
    name: "counter_with_signals",
    description: "Counter that responds to signals",
    schema: [
      count: [type: :integer, default: 0],
      status: [type: :atom, default: :idle]
    ]

  alias Jido.Signal

  @impl true
  def handle_signal(agent, %Signal{type: "counter.increment"} = signal) do
    amount = signal.data[:amount] || 1
    current = agent.state[:count]
    {:ok, agent} = set(agent, count: current + amount)
    {agent, []}
  end

  def handle_signal(agent, %Signal{type: "counter.decrement"} = signal) do
    amount = signal.data[:amount] || 1
    current = agent.state[:count]
    {:ok, agent} = set(agent, count: current - amount)
    {agent, []}
  end

  def handle_signal(agent, %Signal{type: "counter.reset"}) do
    {:ok, agent} = set(agent, count: 0)
    {agent, []}
  end

  def handle_signal(agent, _signal), do: {agent, []}
end
```

Now start the agent under Jido and send signals:

```elixir
{:ok, pid} = Demo.Jido.start_agent(CounterAgentWithSignals, id: "my-counter")
```

Create and send signals:

```elixir
alias Jido.Signal

increment_signal = Signal.new!("counter.increment", %{amount: 10}, source: "/user")
{:ok, agent} = Jido.AgentServer.call(pid, increment_signal)
IO.inspect(agent.state, label: "After increment by 10")

decrement_signal = Signal.new!("counter.decrement", %{amount: 3}, source: "/user")
{:ok, agent} = Jido.AgentServer.call(pid, decrement_signal)
IO.inspect(agent.state, label: "After decrement by 3")
```

For async processing, use `cast/2`:

```elixir
reset_signal = Signal.new!("counter.reset", %{}, source: "/admin")
:ok = Jido.AgentServer.cast(pid, reset_signal)

Process.sleep(50)
{:ok, state} = Jido.AgentServer.state(pid)
IO.inspect(state.agent.state, label: "After reset")
```

## Step 5: Query and Manage Agents

Your instance module provides utilities for managing agents:

```elixir
Demo.Jido.list_agents()
|> IO.inspect(label: "All agents")

Demo.Jido.agent_count()
|> IO.inspect(label: "Agent count")

found_pid = Demo.Jido.whereis("my-counter")
IO.inspect(found_pid == pid, label: "Found by ID?")
```

Stop the agent when done:

```elixir
:ok = Demo.Jido.stop_agent("my-counter")
```

## Summary

You've learned the core Jido workflow:

| Concept | Purpose |
|---------|---------|
| `use Jido, otp_app: :my_app` | Define an instance module for your agents |
| `use Jido.Agent` | Define agents with schemas |
| `cmd/2` | Pure state transformations |
| `MyApp.Jido.start_agent/2` | Run agents in AgentServer |
| `AgentServer.call/3` | Synchronous signal processing |
| `AgentServer.cast/2` | Async signal processing |
| `Signal.new!/3` | Create signals to send to agents |

## Next Steps

- **[Core Loop](core-loop.md)** — Understand "Signal → Action → cmd/2 → {agent, directives}"
- **[Your First Plugin](your-first-plugin.md)** — Package actions with isolated state
- **[Your First Sensor](your-first-sensor.md)** — Feed external events into your agent
- **[Seeing What Happened](observability-intro.md)** — Debug with logs and telemetry
