# Anonymous Workflows
Anonymous workflows are one-call agent runs. They are useful for scripts,
notebooks, jobs, CI tasks, and callbacks where defining a named agent module
would add ceremony without adding useful state.
`Condukt.run/2` accepts a prompt as the first argument:
```elixir
{:ok, text} =
Condukt.run("Summarize README.md in three bullets.",
model: "anthropic:claude-sonnet-4-20250514",
tools: [Condukt.Tools.Read]
)
```
Condukt starts a transient `Condukt.Session`, runs the prompt, returns the
final text, and stops the session. No conversation history is kept across
calls.
## Runtime options
Anonymous workflows accept the same run options as agent runs:
* `:timeout` caps the synchronous call timeout in milliseconds
* `:max_turns` caps tool-use loops
* `:images` attaches images to the user message
They also accept the same session options you would pass to an agent's
`start_link/1`, including `:model`, `:api_key`, `:base_url`,
`:system_prompt`, `:thinking_level`, `:tools`, `:sandbox`, `:cwd`,
`:subagents`, `:session_store`, `:compactor`, `:redactor`, and
`:load_project_instructions`.
Anonymous workflows default `:load_project_instructions` to `false`. Pass
`load_project_instructions: true` when you want `AGENTS.md`, `CLAUDE.md`, and
local skills to shape the transient run.
## Typed input
Use `:input` when you want the prompt to be instructions and the arguments to
be a separate JSON payload:
```elixir
{:ok, text} =
Condukt.run("Review the supplied pull request metadata.",
input: %{repo: "tuist/condukt", pr_number: 42},
input_schema: %{
type: "object",
properties: %{
repo: %{type: "string"},
pr_number: %{type: "integer"}
},
required: ["repo", "pr_number"]
}
)
```
When `:input_schema` is present, Condukt validates the input with JSV before
making an LLM request. Input must be a map.
## Structured output
Use `:output` to require a JSON Schema-shaped result:
```elixir
{:ok, %{verdict: "approve", summary: summary}} =
Condukt.run("Decide a review verdict.",
input: %{repo: "tuist/condukt", pr_number: 42},
output: %{
type: "object",
properties: %{
verdict: %{type: "string", enum: ["approve", "request_changes", "comment"]},
summary: %{type: "string"}
},
required: ["verdict", "summary"]
}
)
```
Structured mode appends a synthetic `submit_result` tool. The model calls that
tool with the final result, Condukt validates the submitted map with JSV, and
the validated value is returned.
If the schema's top-level `properties` keys are atoms, Condukt atomizes the
matching top-level result keys after validation.
## Inline tools
For small workflow-specific tools, use `Condukt.tool/1`:
```elixir
ls =
Condukt.tool(
name: "ls",
description: "Lists files under a glob.",
parameters: %{
type: "object",
properties: %{pattern: %{type: "string"}},
required: ["pattern"]
},
call: fn %{"pattern" => pattern}, context ->
Condukt.Sandbox.glob(context.sandbox, pattern)
end
)
{:ok, text} =
Condukt.run("List Elixir files under lib/.",
tools: [ls]
)
```
Inline tool callbacks receive the same context map as module tools:
`:agent`, `:sandbox`, `:cwd`, and `:opts`. `:opts` is always `[]` for inline
tools.
## Anonymous sub-agents
Anonymous workflows can register sub-agents inline with `:subagents`. Use
`role: [opts]` when the child does not need a named module:
```elixir
{:ok, text} =
Condukt.run("Plan the release notes.",
subagents: [
researcher: [
model: "anthropic:claude-haiku-4-5",
system_prompt: "Find facts and return concise notes.",
tools: [Condukt.Tools.Read]
]
]
)
```
Inline sub-agent opts are normal session opts plus the optional `:input` and
`:output` schemas documented in the sub-agents guide. Anonymous sub-agents
default `:load_project_instructions` to `false`; set it to `true` in the role
opts when the child should load project instructions.
## Errors
Anonymous workflows return `{:error, reason}` for validation failures, LLM
errors, and session startup failures.
Common structured workflow reasons include:
* `{:invalid_input, %JSV.ValidationError{}}`
* `{:invalid_output, %JSV.ValidationError{}}`
* `{:invalid_input, :input_must_be_a_map}`
* `:no_result_submitted`
## Choosing an API
Use anonymous workflows when the task fits in one call and no module-level
agent identity is useful.
Use `operation/2` when you want a named compile-time entrypoint on an agent
module.
Use a supervised agent process when you need long-lived state, conversation
history, streaming interaction, or OTP supervision.