Build a claude job's args map without knowing claude_wrapper or the CLI.
new/1 is the first-class front door: a keyword list with atom keys and native
Elixir values in, the string-keyed JSON map Oban stores out. It is the
preferred way to construct args; ObanClaude.run/2 and ObanClaude.Worker
still accept a raw string-keyed map directly as the low-level escape hatch.
ObanClaude.Args.new(prompt: "summarize the repo",
working_dir: "/repo",
permission_mode: :plan)
#=> %{"prompt" => "summarize the repo",
# "working_dir" => "/repo",
# "permission_mode" => "plan"}The result is a plain map, so it drops straight into a worker:
MyApp.ClaudeJob.new(ObanClaude.Args.new(prompt: "...")) |> Oban.insert()Worker defaults
defaults/1 is the same builder with :prompt optional, for the worker's
:args (the constant, prompt-less config). It evaluates at compile time, so it
works directly in the use:
use ObanClaude.Worker,
queue: :claude,
args: ObanClaude.Args.defaults(working_dir: ".", model: "sonnet",
permission_mode: :bypass_permissions)Job metadata
The :meta option carries non-claude values (an issue number, a correlation id)
through to the Oban job args, where handle_result/2 and telemetry can read
them. It is merged untouched (keys stringified) and is not validated as a claude
option:
ObanClaude.Args.new(prompt: "...", meta: %{"issue" => "173"})
#=> %{"prompt" => "...", "issue" => "173"}Validation
Unlike the raw-map path (which forwards known keys and silently ignores the
rest), the builder validates against the schema below: unknown keys raise, and
each option's type (including the :permission_mode and :effort vocabularies)
is checked. Errors surface at construction / enqueue time rather than when the
job runs.
Options
:prompt(String.t/0) - Required. The claude prompt. The only required option fornew/1.:model(String.t/0) - Model name, e.g."sonnet"or"opus".:fallback_model(String.t/0) - Model to fall back to if the primary is unavailable.:working_dir(String.t/0) - Directory claude runs in.:add_dir(list ofString.t/0) - Extra directories claude may access.:system_prompt(String.t/0) - Replace claude's system prompt.:append_system_prompt(String.t/0) - Append to claude's system prompt.:permission_mode- How claude handles tool-permission prompts.:allowed_tools(list ofString.t/0) - Whitelist of tools claude may use.:disallowed_tools(list ofString.t/0) - Blacklist of tools claude may not use.:mcp_config(list ofString.t/0) - MCP server config file paths.:agent(String.t/0) - Named agent/subagent to run as.:effort- Reasoning effort level.:max_turns(pos_integer/0) - Cap on agent turns in the run.:max_budget_usd- Cost ceiling for the run, in USD.:timeout(pos_integer/0) - Subprocess timeout in milliseconds.:json_schema(String.t/0) - A JSON schema string for structured output.:worktree- Run in a git worktree (--worktree).truefor an ephemeral worktree, a string for a named one (reusable across jobs -- e.g."issue-173"). Requiresworking_dirto be a git repo. Recommended for full-auto workers that write to a repo -- set it indefaults/1.:meta- Non-claude metadata merged into the args map untouched (keys stringified). For valueshandle_result/2or telemetry needs -- an issue number, a correlation id. Explicit claude options win on a key collision.
Summary
Functions
Build a worker-level defaults map: the same as new/1, but :prompt is
optional (worker :args are the prompt-less config the per-job args fill in).
Because it evaluates at compile time, it can be used directly in the worker's
use (see "Worker defaults" above).
@spec keys() :: [atom()]
The options the builder accepts.
Build a string-keyed args map from a keyword list of atom-keyed options.
Validates opts against the schema documented above (see "Options"). Raises
NimbleOptions.ValidationError on a missing :prompt, an unknown key, or a
value of the wrong type. Returns the map Oban serializes as the job's args.