WardrikHTTP

Serves Wardrik over HTTP. Every operation is a JSON route, and agents' events stream as server-sent events.

Install

def deps do
  [
    {:wardrik, "~> 0.1.0-rc.2"},
    {:wardrik_http, "~> 0.1.0-rc.2"}
  ]
end

Serve it

children = [
  MyApp.AgentRuntime,
  {Wardrik.HTTP,
   wardrik: MyApp.AgentRuntime, authenticator: {MyAppWeb.WardrikSession, []}, port: 4000}
]

Authenticate requests

An authenticator turns each request into a scope. Wardrik's authorizer then decides what it may do. See Who may do what.

defmodule MyAppWeb.WardrikSession do
  @behaviour WardrikHTTP.Authenticator

  @impl true
  def authenticate(%{conn: conn, wardrik: wardrik}, _opts) do
    with ["Bearer " <> token] <- Plug.Conn.get_req_header(conn, "authorization"),
         {:ok, id} <- Phoenix.Token.verify(MyAppWeb.Endpoint, "wardrik", token, max_age: 86_400) do
      {:ok, Wardrik.as(wardrik, id)}
    else
      _not_signed_in -> {:error, Wardrik.Error.new(:unauthorized, "Sign in first.")}
    end
  end
end

Talk to agents

curl -X PUT localhost:4000/v1/agents/agt_1 \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"model": "anthropic:claude-haiku-4-5", "instructions": "You watch the incident queue."}'

curl -X POST localhost:4000/v1/agents/agt_1/messages \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"content": "What is on fire?"}'
#=> {"message": {"id": "msg_Xq3f...", "cursor": "W1siYWd0XzEiLG51bGwsNDFdXQ"}}

curl -N localhost:4000/v1/agents/agt_1/events?after=W1siYWd0XzEiLG51bGwsNDFdXQ \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: text/event-stream"
#=> id: W1siYWd0XzEiLG51bGwsNDNdXQ
#=> data: {"specversion":"1.0","type":"wardrik.run.completed",...}

Receive webhooks

A trigger's webhook takes requests at POST /v1/hooks/{agent}/{trigger}, with no authenticator. The request proves itself with the trigger's secret. See Trigger agents.

If Phoenix parses bodies first, keep the raw bytes for the signature check:

plug Plug.Parsers,
  parsers: [:urlencoded, :multipart, :json],
  json_decoder: Phoenix.json_library(),
  body_reader: Wardrik.HTTP.body_reader()

Run tools in your own process

A tool worker is your program, offering agents tools over a WebSocket to /v1/workers. Wardrik is the MCP client. The tools run in your process, with your code and keys.

Wardrik.Agent.define(scope, "agt_1",
  model: "anthropic:claude-haiku-4-5",
  tools: ["workers/*"],
  policy: [ask: ["workers/refund_order"]]
)

Sign people in

With Wardrik's :oauth set, /oauth/ serves the pages a sign-in returns to. Set its page to that URL. See Credentials and sign-ins.

License

Apache-2.0