The default Oban worker for agent turns: runs claude, then routes the
outcome back to the owning ObanClaude.Agent.Instance.
The owning agent's id rides in the job's meta ("agent_id"), where
ObanClaude.Agent.Instance puts it at enqueue time. A job without an
"agent_id" (enqueued by hand) runs normally and reports to no one.
Retry-awareness
The routing is terminal-aware, so a worker with retries reports one logical turn, not one event per attempt:
- a success, a
{:cancel, _}verdict, or an{:error, _}on the final attempt is terminal ->ObanClaude.Agent.job_finished/2 - an
{:error, _}with attempts remaining, or a{:snooze, _}, means Oban will re-run the job ->ObanClaude.Agent.job_retrying/2, which keeps the machine in:runningand re-arms its watchdog
This worker itself stays at max_attempts: 1 -- every retry is a fresh paid
claude call, so retrying is an explicit opt-in, not a default. To opt in,
point the agent's :worker config at your own worker and delegate the
callbacks here:
defmodule MyApp.RetryingAgentJob do
use ObanClaude.Worker, queue: :agents, max_attempts: 3
@impl ObanClaude.Worker
def handle_result(result, job), do: ObanClaude.Agent.Job.handle_result(result, job)
@impl ObanClaude.Worker
def handle_error(verdict, payload, job),
do: ObanClaude.Agent.Job.handle_error(verdict, payload, job)
end