ClaudeWrapper.Query (ClaudeWrapper v0.14.0)

Copy Markdown View Source

Query command -- the primary interface for executing prompts.

Wraps claude -p <prompt> with the full set of CLI flags.

Usage

config = ClaudeWrapper.Config.new(working_dir: "/path/to/project")

# Build a query
query = ClaudeWrapper.Query.new("Fix the failing test")
  |> ClaudeWrapper.Query.model("sonnet")
  |> ClaudeWrapper.Query.max_turns(5)
  |> ClaudeWrapper.Query.permission_mode(:bypass_permissions)

# Execute (one-shot, returns full result)
{:ok, result} = ClaudeWrapper.Query.execute(query, config)

# Or stream events
ClaudeWrapper.Query.stream(query, config)
|> Stream.each(&IO.inspect/1)
|> Stream.run()

Summary

Functions

Add a directory for tool access.

Set agent name.

Provide custom agents as JSON.

Add an allowed tool.

Append to the system prompt.

Append to the system prompt from a file (--append-system-prompt-file). Verified against claude CLI 2.1.170 (hidden from --help).

Apply a keyword list of options to a query, calling the equivalent Query setter for each known key. Unknown keys are silently ignored.

Minimal mode: skip hooks, LSP, plugins, and settings (--bare).

Set beta feature header(s).

Enable the SendUserMessage tool for agent-to-user communication (--brief).

Continue the most recent session.

Bypass all permission checks. Use in isolated worktrees.

Set debug log file.

Set debug filter.

Disable all slash commands / skills (--disable-slash-commands).

Add a disallowed tool.

Set effort level.

Exclude dynamic system-prompt sections (--exclude-dynamic-system-prompt-sections).

Execute the query synchronously, returning a parsed %Result{}.

Set a fallback model.

Add a file resource.

Fork to a new session.

Resume a session linked to a PR (--from-pr <number|url>).

Seal the ambient ~/.claude config so a programmatic run's surface is exactly what was provided explicitly.

Include hook lifecycle events in the output stream (--include-hook-events).

Include partial messages in streaming output.

Set input format.

Set JSON schema for structured output.

Set maximum budget in USD.

Cap the thinking-token budget (--max-thinking-tokens), a finer control than --effort. Verified against claude CLI 2.1.170 (hidden from --help).

Set maximum turns.

Add an MCP config file path.

Set the model (e.g. "sonnet", "opus", "haiku").

Set a display name for the session (--name).

Create a new query with the given prompt.

Disable session persistence.

Set output format.

Set permission mode.

Delegate permission decisions to a custom MCP tool (--permission-prompt-tool <tool>) for programmatic headless gating. Verified against claude CLI 2.1.170 (hidden from --help).

Add a plugin directory.

Fetch a plugin .zip from a URL (--plugin-url). Repeatable.

Enable prompt suggestions (--prompt-suggestions).

Re-emit user messages from stdin (--replay-user-messages). Mainly for stream/duplex use.

Resume a specific session by ID.

Start with all customizations disabled (--safe-mode).

Use a specific session ID.

Set settings source list.

Set settings JSON.

The spawn-time flag subset of a query, for a long-lived ClaudeWrapper.DuplexSession.

Execute the query and return a lazy stream of %StreamEvent{}.

Only use servers from --mcp-config.

Set the system prompt (overrides default).

Set the system prompt from a file (--system-prompt-file), avoiding ARG_MAX limits from inlining a large prompt as argv. Verified against claude CLI 2.1.170 (hidden from --help).

Create tmux session.

Build the shell command string (for debugging).

Add a tool.

Create a git worktree for execution (--worktree). See worktree/2 for a named worktree.

Create a named git worktree for execution (--worktree <name>).

Types

effort()

@type effort() :: :low | :medium | :high | :xhigh | :max

hermetic()

@type hermetic() :: :full | :project

input_format()

@type input_format() :: :text | :stream_json

output_format()

@type output_format() :: :text | :json | :stream_json

permission_mode()

@type permission_mode() ::
  :default | :accept_edits | :bypass_permissions | :dont_ask | :plan | :auto

t()

@type t() :: %ClaudeWrapper.Query{
  add_dir: [String.t()],
  agent: String.t() | nil,
  agents_json: String.t() | nil,
  allowed_tools: [String.t()],
  append_system_prompt: String.t() | nil,
  append_system_prompt_file: String.t() | nil,
  bare: boolean(),
  betas: String.t() | [String.t()] | nil,
  brief: boolean(),
  continue_session: boolean(),
  dangerously_skip_permissions: boolean(),
  debug_file: String.t() | nil,
  debug_filter: String.t() | nil,
  disable_slash_commands: boolean(),
  disallowed_tools: [String.t()],
  effort: effort() | nil,
  exclude_dynamic_system_prompt_sections: boolean(),
  fallback_model: String.t() | nil,
  files: [String.t()],
  fork_session: boolean(),
  from_pr: String.t() | nil,
  hermetic: hermetic() | nil,
  include_hook_events: boolean(),
  include_partial_messages: boolean(),
  input_format: input_format() | nil,
  json_schema: String.t() | nil,
  max_budget_usd: float() | nil,
  max_thinking_tokens: pos_integer() | nil,
  max_turns: pos_integer() | nil,
  mcp_config: [String.t()],
  model: String.t() | nil,
  name: String.t() | nil,
  no_session_persistence: boolean(),
  output_format: output_format() | nil,
  permission_mode: permission_mode() | nil,
  permission_prompt_tool: String.t() | nil,
  plugin_dirs: [String.t()],
  plugin_urls: [String.t()],
  prompt: String.t(),
  prompt_suggestions: boolean(),
  replay_user_messages: boolean(),
  resume: String.t() | nil,
  safe_mode: boolean(),
  session_id: String.t() | nil,
  setting_sources: String.t() | nil,
  settings: String.t() | nil,
  strict_mcp_config: boolean(),
  system_prompt: String.t() | nil,
  system_prompt_file: String.t() | nil,
  tmux: boolean(),
  tools: [String.t()],
  worktree: boolean() | String.t()
}

Functions

add_dir(q, dir)

@spec add_dir(t(), String.t()) :: t()

Add a directory for tool access.

agent(q, name)

@spec agent(t(), String.t()) :: t()

Set agent name.

agents_json(q, json)

@spec agents_json(t(), String.t()) :: t()

Provide custom agents as JSON.

allowed_tool(q, pattern)

@spec allowed_tool(t(), String.t() | ClaudeWrapper.ToolPattern.t()) :: t()

Add an allowed tool.

Accepts either a plain CLI-format string ("Bash(git log:*)") or a ClaudeWrapper.ToolPattern.t/0, which is rendered to its string form. The stored field stays a list of strings.

append_system_prompt(q, prompt)

@spec append_system_prompt(t(), String.t()) :: t()

Append to the system prompt.

append_system_prompt_file(q, path)

@spec append_system_prompt_file(t(), String.t()) :: t()

Append to the system prompt from a file (--append-system-prompt-file). Verified against claude CLI 2.1.170 (hidden from --help).

apply_opts(query, opts)

@spec apply_opts(
  t(),
  keyword()
) :: t()

Apply a keyword list of options to a query, calling the equivalent Query setter for each known key. Unknown keys are silently ignored.

This is the shared mapping used by ClaudeWrapper.query/2, ClaudeWrapper.stream/2, and ClaudeWrapper.Session.send/3. It exists so the opt-to-setter mapping lives in one place rather than being duplicated across each surface.

Boolean opts (e.g. :worktree, :dangerously_skip_permissions) are applied when the value is true and ignored when false. List opts (e.g. :allowed_tools, :add_dir) reduce over their list, applying the per-item setter for each entry.

Examples

iex> q = ClaudeWrapper.Query.new("hi")
iex> q = ClaudeWrapper.Query.apply_opts(q, model: "sonnet", max_turns: 3, worktree: true)
iex> q.model
"sonnet"
iex> q.max_turns
3
iex> q.worktree
true

bare(q)

@spec bare(t()) :: t()

Minimal mode: skip hooks, LSP, plugins, and settings (--bare).

betas(q, betas)

@spec betas(t(), String.t() | [String.t()]) :: t()

Set beta feature header(s).

Accepts a single string or a list -- the CLI's --betas is variadic, so a list emits one --betas flag followed by every value (a single string is still accepted, unchanged).

brief(q)

@spec brief(t()) :: t()

Enable the SendUserMessage tool for agent-to-user communication (--brief).

continue_session(q)

@spec continue_session(t()) :: t()

Continue the most recent session.

dangerously_skip_permissions(q)

@spec dangerously_skip_permissions(t()) :: t()

Bypass all permission checks. Use in isolated worktrees.

debug_file(q, path)

@spec debug_file(t(), String.t()) :: t()

Set debug log file.

debug_filter(q, filter)

@spec debug_filter(t(), String.t()) :: t()

Set debug filter.

disable_slash_commands(q)

@spec disable_slash_commands(t()) :: t()

Disable all slash commands / skills (--disable-slash-commands).

disallowed_tool(q, pattern)

@spec disallowed_tool(t(), String.t() | ClaudeWrapper.ToolPattern.t()) :: t()

Add a disallowed tool.

Accepts either a plain CLI-format string or a ClaudeWrapper.ToolPattern.t/0, mirroring allowed_tool/2.

effort(q, level)

@spec effort(t(), effort()) :: t()

Set effort level.

exclude_dynamic_system_prompt_sections(q)

@spec exclude_dynamic_system_prompt_sections(t()) :: t()

Exclude dynamic system-prompt sections (--exclude-dynamic-system-prompt-sections).

execute(query, config)

@spec execute(t(), ClaudeWrapper.Config.t()) ::
  {:ok, ClaudeWrapper.Result.t()} | {:error, ClaudeWrapper.Error.t()}

Execute the query synchronously, returning a parsed %Result{}.

Automatically sets --output-format json for parsing.

fallback_model(q, model)

@spec fallback_model(t(), String.t()) :: t()

Set a fallback model.

file(q, path)

@spec file(t(), String.t()) :: t()

Add a file resource.

fork_session(q)

@spec fork_session(t()) :: t()

Fork to a new session.

from_pr(q, pr)

@spec from_pr(t(), String.t()) :: t()

Resume a session linked to a PR (--from-pr <number|url>).

Analogous to resume/2 but keyed on a pull request rather than a session id. The value is a PR number or URL.

hermetic(q, scope)

@spec hermetic(t(), hermetic()) :: t()

Seal the ambient ~/.claude config so a programmatic run's surface is exactly what was provided explicitly.

A preset over three flags, expanded at flag-build time (never here), so the seal is order-independent and an explicit setting_sources/2 always wins over the scope's default:

  • --setting-sources (the ambient-config seal)
  • --strict-mcp-config (only servers from --mcp-config)
  • --exclude-dynamic-system-prompt-sections (reproducibility)

The scope sets the seal level:

  • :full -> --setting-sources "" -- drops user + project + local ambient config; only claude's built-in agents remain.
  • :project -> --setting-sources user -- seals project + local ambient config, keeps the user's global ~/.claude.

Hermetic seals the promptspace WITHOUT changing auth: it never emits --bare (which would force ANTHROPIC_API_KEY billing). OAuth / keychain / subscription auth is untouched.

include_hook_events(q)

@spec include_hook_events(t()) :: t()

Include hook lifecycle events in the output stream (--include-hook-events).

include_partial_messages(q)

@spec include_partial_messages(t()) :: t()

Include partial messages in streaming output.

input_format(q, fmt)

@spec input_format(t(), input_format()) :: t()

Set input format.

json_schema(q, schema)

@spec json_schema(t(), String.t()) :: t()

Set JSON schema for structured output.

max_budget_usd(q, budget)

@spec max_budget_usd(t(), float()) :: t()

Set maximum budget in USD.

max_thinking_tokens(q, n)

@spec max_thinking_tokens(t(), pos_integer()) :: t()

Cap the thinking-token budget (--max-thinking-tokens), a finer control than --effort. Verified against claude CLI 2.1.170 (hidden from --help).

max_turns(q, n)

@spec max_turns(t(), pos_integer()) :: t()

Set maximum turns.

mcp_config(q, path)

@spec mcp_config(t(), String.t()) :: t()

Add an MCP config file path.

model(q, model)

@spec model(t(), String.t()) :: t()

Set the model (e.g. "sonnet", "opus", "haiku").

name(q, name)

@spec name(t(), String.t()) :: t()

Set a display name for the session (--name).

new(prompt)

@spec new(String.t()) :: t()

Create a new query with the given prompt.

no_session_persistence(q)

@spec no_session_persistence(t()) :: t()

Disable session persistence.

output_format(q, fmt)

@spec output_format(t(), output_format()) :: t()

Set output format.

permission_mode(q, mode)

@spec permission_mode(t(), permission_mode()) :: t()

Set permission mode.

permission_prompt_tool(q, tool)

@spec permission_prompt_tool(t(), String.t()) :: t()

Delegate permission decisions to a custom MCP tool (--permission-prompt-tool <tool>) for programmatic headless gating. Verified against claude CLI 2.1.170 (hidden from --help).

plugin_dir(q, dir)

@spec plugin_dir(t(), String.t()) :: t()

Add a plugin directory.

plugin_url(q, url)

@spec plugin_url(t(), String.t()) :: t()

Fetch a plugin .zip from a URL (--plugin-url). Repeatable.

prompt_suggestions(q)

@spec prompt_suggestions(t()) :: t()

Enable prompt suggestions (--prompt-suggestions).

replay_user_messages(q)

@spec replay_user_messages(t()) :: t()

Re-emit user messages from stdin (--replay-user-messages). Mainly for stream/duplex use.

resume(q, id)

@spec resume(t(), String.t()) :: t()

Resume a specific session by ID.

safe_mode(q)

@spec safe_mode(t()) :: t()

Start with all customizations disabled (--safe-mode).

session_id(q, id)

@spec session_id(t(), String.t()) :: t()

Use a specific session ID.

setting_sources(q, sources)

@spec setting_sources(t(), String.t()) :: t()

Set settings source list.

settings(q, json)

@spec settings(t(), String.t()) :: t()

Set settings JSON.

spawn_args(q)

@spec spawn_args(t()) :: [String.t()]

The spawn-time flag subset of a query, for a long-lived ClaudeWrapper.DuplexSession.

Reuses build_args/1 (the single source of flag emission, so the duplex and one-shot paths cannot drift), then removes the flags a duplex session owns itself: the transport formats (--output-format / --input-format / --include-partial-messages, which the session fixes to its stream-json protocol) and the leading --print <prompt> pair (in duplex the prompt is a per-turn stream-json message, not an argv). Everything else -- model, system prompt, permission mode, tool allow/deny lists, mcp config, effort, turn/budget caps, session continuity, and so on -- is spawn-safe and passes through.

stream(query, config)

@spec stream(t(), ClaudeWrapper.Config.t()) :: Enumerable.t()

Execute the query and return a lazy stream of %StreamEvent{}.

Uses a Port with :line mode to read NDJSON output line-by-line. The port is opened when the stream is consumed and closed when the stream terminates.

A clean run ends with a terminal %StreamEvent{type: "result"}. If the stream halts without one -- an idle timeout (Config.timeout is not a whole-run bound here; only the per-frame idle deadline applies), a non-zero exit, or a spawn failure -- the stream ends with a terminal %StreamEvent{type: "error", data: %{"error" => "stream_truncated"}} so the truncation is observable. Note the default runner orphans a stalled subprocess; use the ClaudeWrapper.Runner.Forcola runner for leak-free termination.

strict_mcp_config(q)

@spec strict_mcp_config(t()) :: t()

Only use servers from --mcp-config.

system_prompt(q, prompt)

@spec system_prompt(t(), String.t()) :: t()

Set the system prompt (overrides default).

system_prompt_file(q, path)

@spec system_prompt_file(t(), String.t()) :: t()

Set the system prompt from a file (--system-prompt-file), avoiding ARG_MAX limits from inlining a large prompt as argv. Verified against claude CLI 2.1.170 (hidden from --help).

tmux(q)

@spec tmux(t()) :: t()

Create tmux session.

to_command_string(query, config)

@spec to_command_string(t(), ClaudeWrapper.Config.t()) :: String.t()

Build the shell command string (for debugging).

tool(q, tool)

@spec tool(t(), String.t()) :: t()

Add a tool.

worktree(q)

@spec worktree(t()) :: t()

Create a git worktree for execution (--worktree). See worktree/2 for a named worktree.

worktree(q, name)

@spec worktree(t(), String.t()) :: t()

Create a named git worktree for execution (--worktree <name>).