Operations

Copy Markdown

Everything people and programs do with agents is an operation. Each is defined once, and works the same from your code, HTTP, Slack or a terminal.

Setup

In a fresh IEx session:

Mix.install([{:wardrik, "~> 0.1.0-rc.1"}])

{:ok, _} = Wardrik.start_link(name: MyApp.AgentRuntime)
scope = Wardrik.as(MyApp.AgentRuntime, "acme/@maria", roles: [:owner], resources: ["acme/@maria/*"])

As functions

Each operation is a function named by its ID. agent.define is Wardrik.Agent.define/3:

{:ok, books} =
  Wardrik.Agent.define(scope, "acme/@maria/books",
    model: "anthropic:claude-haiku-4-5",
    instructions: "You keep Maria's books."
  )

Wardrik.Agent.read(scope, books)
#=> {:ok,
#=>  %Wardrik.Agent{
#=>    id: "acme/@maria/books",
#=>    name: "books",
#=>    status: :idle,
#=>    node: "nonode@nohost",
#=>    pending: 0,
#=>    activity: %Wardrik.Activity{doing: [], ...},
#=>    interrupts: [],
#=>    cursor: "eyJhY21lL0BtYXJpYS9ib29rcyI6MX0"
#=>  }}

Wardrik.Agents.list(scope)
#=> {:ok, [%Wardrik.Agent{id: "acme/@maria/books", status: :idle, ...}]}

Wardrik.Agent.cancel(scope, books)
#=> :ok

Wardrik.Agent.read(scope, "acme/@maria/ledger")
#=> {:error, %Wardrik.Error{type: :not_found, message: "There's no agent acme/@maria/ledger."}}

agent.ask is Wardrik.Agent.ask/3, and needs the model's API key; see Talk to agents.

Each function takes, in order:

  1. the scope.
  2. the operation's path parameters, each as text or as the struct it names, like %Wardrik.Agent{} for an agent or %Wardrik.Interrupt{} for a call it waits on.
  3. the rest of its input, as a keyword list.

Each returns a struct, a list of them, or :ok. It returns {:error, %Wardrik.Error{}}, with the error's type and message, when it fails. Operations that can be streamed also have a stream_ function; see Events and the audit.

ReturnsOperations
%Wardrik.Agent{}define, read, clear, spawn, stop, move; a list from Wardrik.Agents.list/2
%Wardrik.Message{}ask
[%Wardrik.Decision{}]decide, approve, deny
[%Wardrik.Interrupt{}]Wardrik.Interrupts.list/2
%Wardrik.Page{} of %Wardrik.Event{}events, Wardrik.Events.list/2, Wardrik.Audit.list/2
%Wardrik.Timeline{}, %Wardrik.Runs{}timeline, runs
[%Wardrik.Call{}], %Wardrik.Authorization{}calls, authorization
:okcancel, forget, kill

An event's data, an activity's doing and a timeline's items stay as the protocol's maps, since their shape depends on their type.

ModuleOperations
Wardrik.AgentOne agent: define, ask, read, cancel, decide, approve, deny, stop, spawn, clear, forget, move, its triggers, calls, events, timeline and runs.
Wardrik.AgentsThe agents a scope can see: list, cancel and forget them.
Wardrik.InterruptsWhat agents wait on.
Wardrik.EventsAgents' events.
Wardrik.AuditWhat people did.
Wardrik.TokensAPI tokens.
Wardrik.ConnectionsAccounts people and orgs connect.
Wardrik.MCPServersMCP servers orgs and people add.
Wardrik.CeilingsWhat orgs have spent.
Wardrik.DeploymentNodes and reloading.
Wardrik.HookWebhook requests to triggers.

By ID

Wardrik.run/3 runs an operation by its ID. It takes and returns the protocol's JSON, which is how a surface you build reaches operations:

Wardrik.run(scope, "agent.read", %{"agent" => "acme/@maria/books"})
#=> {:ok,
#=>  %{
#=>    "agent" => %{"id" => "acme/@maria/books", "name" => "books"},
#=>    "status" => "idle",
#=>    "cursor" => "eyJhY21lL0BtYXJpYS9ib29rcyI6MX0",
#=>    ...
#=>  }}