Configuration
How do you configure an agentic workflow without repeating yourself across dozens of actions? Agent Actions uses a three-level configuration hierarchy that lets you set defaults once and override them where needed. Higher specificity wins—action settings override agentic workflow defaults, which override project defaults.
Think of it like CSS specificity: project settings are the base styles, agentic workflow defaults are class-level overrides, and action-specific settings are inline styles that take precedence.
The diagram below shows how configuration cascades from project-level down to individual actions:
Notice that the most specific level (action inline fields) has final say. This means you can establish sensible defaults project-wide but still customize individual actions when needed.
Project Configuration
The agent_actions.yml file in your project root defines global settings:
# agent_actions.yml
default_agent_config:
api_key: OPENAI_API_KEY
model_name: gpt-4o-mini
model_vendor: openai
chunk_config:
chunk_size: 4000
chunk_overlap: 500
schema_path: schema
tool_path: ["tools"]
seed_data_path: seed_data
required_by_default: false
| Field | Description |
|---|---|
default_agent_config | Default settings inherited by all actions, including chunk_config — see Chunking. Only keys nested here reach an action; a chunk_config: at the file's top level is read by nothing |
schema_path | Directory containing output schemas (default: schema) |
tool_path | Directories to scan for custom tools |
seed_data_path | Directory for static reference data (default: seed_data) |
required_by_default | When true, flat schema fields (fields: list) are required unless marked optional: true; when false (default) they are optional unless marked required: true. Applies project-wide; a schema declaring its own required_by_default overrides it. |
Agentic Workflow Configuration
Each agentic workflow YAML file defines defaults and actions. Let's explore how an agentic workflow brings together model settings, execution modes, and action definitions:
# agent_config/my_workflow.yml
name: my_workflow
description: "Extract and validate facts"
# version: "1.0.0" # Optional — for your own bookkeeping
defaults:
model_vendor: openai
model_name: gpt-4o-mini
json_mode: true
granularity: Record
run_mode: batch
actions:
- name: extract_facts
prompt: $prompts.extract_facts
schema: facts_schema
The top level takes exactly these keys, and refuses any other — a misspelled
defaults: would otherwise be dropped in silence, taking every setting in the block
with it:
| Key | Meaning |
|---|---|
name | Workflow name (required) |
description | Workflow description (required) |
version | Optional, for your own bookkeeping |
defaults | Settings inherited by every action |
actions | The actions themselves (required) |
tool_path | Where this workflow's UDFs live. Takes precedence over the default config and over tool_path in agent_actions.yml |
storage | Maintenance knobs: prompt_trace_retention_runs and source_data_ttl_days. Despite the first one's name its unit is calendar days, not runs. 0 means never prune; omitting a key takes the framework default, which for traces is 10 days and does prune |
Model settings such as model_vendor belong under defaults:, not at the top level.
See Defaults for the complete inheritance system.
Action Configuration
Each action can override any default. Consider what happens when you need one action to use a different model or run in a different mode—you simply specify those fields on the action itself:
actions:
- name: extract_facts
intent: "Extract key facts from content"
dependencies: [prior_action] # Input source
# Model
model_vendor: openai
model_name: gpt-4o-mini
# Prompt & Schema
prompt: $prompts.extract_facts
schema: facts_schema
json_mode: true
# Execution
run_mode: batch
granularity: Record
# Conditional
guard:
condition: "source.content != ''"
on_false: filter
Core Action Fields
| Field | Type | Description |
|---|---|---|
name | string | Unique action identifier |
intent | string | Human-readable description |
kind | string | llm (default) or tool |
dependencies | list | Upstream actions to wait for |
prompt | string | Inline prompt or $store.template reference |
schema | string | Output validation schema |
context_scope | object | Control data visibility: observe, drop, passthrough, seed — see Context Scope |
Model Fields
| Field | Type | Description |
|---|---|---|
model_vendor | string | Provider: openai, anthropic, google, groq, cohere, ollama_local, ollama_cloud |
model_name | string | Model identifier (e.g., gpt-4o-mini) |
api_key | string | Environment variable name for API key |
temperature | float | LLM temperature (0.0-2.0) |
max_tokens | integer | Maximum response tokens |
top_p | float | Top-p (nucleus) sampling (0.0-1.0) |
stop | string/list | Stop sequence(s) to end generation |
:::note Vendor-Specific Parameter Mapping
Generation parameters (temperature, max_tokens, top_p, stop) are mapped to vendor-specific API keys automatically:
- OpenAI / Groq: Parameters passed through as-is. OpenAI and Groq also support
frequency_penaltyandpresence_penalty. - Anthropic:
stop→stop_sequences(string values are wrapped in a list) - Gemini:
max_tokens→max_output_tokens,stop→stop_sequences - Cohere:
top_p→p,stop→stop_sequences - Ollama:
max_tokens→num_predict, parameters placed inoptionsdict.stopstrings are wrapped in a list. :::
Execution Fields
| Field | Type | Description |
|---|---|---|
run_mode | string | online or batch — see Run Modes |
granularity | string | record or file — see Granularity |
guard | object | Conditional execution — see Guards |
is_operational | boolean | Enable/disable action (default: true) |
on_empty | string | What an empty answer does: warn (default) fails the record and the run goes on, error fails the action, skip passes the record through as a tombstone |
retry | object | Retry configuration for transport-layer failures |
:::note Granularity Constraints
- File granularity is supported for tool and HITL actions (
kind: tool,kind: hitl) - Guards are supported with File granularity; the guard is evaluated per record before the
action receives the file, against the record as stored rather than the
context_scope-shaped view — so a field the action drops still answers a clause. See Guards. :::
Input Source
A workflow can replace the default staging/ input with a local folder and optional file-type filter. data_source is set under defaults:, where the workflow's first actions read it; the loader refuses it on an action:
defaults:
data_source:
type: local
folder: ./data
file_type: [json]
Validation Fields
| Field | Type | Description |
|---|---|---|
json_mode | boolean | Enable structured JSON output |
expect | object | Output rules and repair policy (see Expectations) |
expect | object | Output expectations and their enforcement policy (see AI Expectations) |
Tool Action Fields
| Field | Type | Description |
|---|---|---|
impl | string | Python function name (required for kind: tool) |
Tool actions support both Record and File granularity. File granularity allows the tool to process all records at once, enabling operations like deduplication, aggregation, and batch exports.
Vendor Support
| Vendor | model_vendor | Batch API | Example Models |
|---|---|---|---|
| OpenAI | openai | ✅ | gpt-4o, gpt-4o-mini |
| Anthropic | anthropic | ✅ | claude-sonnet-4-20250514 |
google | ✅ | gemini-2.0-flash | |
| Groq | groq | ✅ | llama-3.3-70b-versatile |
| Cohere | cohere | ❌ | command-r-plus |
| Ollama (local) | ollama_local | ✅ | llama3, mistral |
| Ollama (cloud) | ollama_cloud | ✅ | gpt-oss:120b-cloud |
Environment Variables
You might wonder why API keys are specified as variable names rather than values. Agent Actions references environment variables by name, keeping secrets out of your configuration files:
api_key: OPENAI_API_KEY # Uses $OPENAI_API_KEY from environment
API Keys
| Variable | Provider |
|---|---|
OPENAI_API_KEY | OpenAI |
ANTHROPIC_API_KEY | Anthropic |
GOOGLE_API_KEY | Google Gemini |
GROQ_API_KEY | Groq |
OLLAMA_HOST | Ollama (default: http://localhost:11434) |
Runtime Variables
| Variable | Default | Description |
|---|---|---|
AGENT_ACTIONS_LOG_LEVEL | INFO | Log level (DEBUG, INFO, WARNING, ERROR) |
AGENT_ACTIONS_DEBUG | 0 | Enable debug mode |
AGAC_RECORD_LIMIT | unset | Cap each action at this many records per input file, overriding a larger record_limit and applying to actions that set none. --record-limit takes precedence when both are set, and can raise this value as well as lower it. For running a project cheaply from outside it — a smoke check, a quick sanity pass. On a workflow you have already run it is not read-only: a limit smaller than what a completed action already processed differs from the one it stored, so it re-executes under this one and its output is rewritten to the smaller set. A value at or above what an untruncated run processed cannot cut anything and leaves the action alone. That needs a run able to say what it processed: one that completed before these counts existed, or one that lost an input file to an error, keeps the coarse rule and re-executes on any change. Unset it, or use a scratch project, when the stored output matters. An action that actually drops records logs a warning naming this variable, since a truncated run otherwise looks complete; an action that had nothing to drop stays quiet. A value below 1, or one that is not an integer, fails rather than being ignored — checked while the workflow is assembled, so it stops any command that loads one, read-only ones like agac inspect included. An empty or blank value reads as unset, since that is what a shell means by AGAC_RECORD_LIMIT=. Never excludes a record that agac retry is re-running, since retry selects by id. |
AGAC_FILE_LIMIT | unset | Stop each action after this many input files, overriding a larger file_limit and applying to actions that set none. It counts files the action got through, so one that fails does not spend the budget. --file-limit takes precedence when both are set, and can raise this value as well as lower it. The other axis of the same job: AGAC_RECORD_LIMIT shrinks each file, this shrinks how many are read, and a run is proportional to both. On a workflow you have already run it is not read-only, for the same reason: the limit it applies differs from the one the completed actions stored, so they re-execute under it. Files the shorter walk does not reach keep the output the earlier run wrote there, so what you end up with is the old output with the walked files replaced rather than a smaller fresh copy. An action whose walk actually stops short logs a warning naming this variable; one that reached every file stays quiet. A value below 1, or one that is not an integer, fails rather than being ignored, and fails before any action starts — the walk does not consult a file limit until a file has been processed, so it is checked while the workflow is assembled, which also stops read-only commands like agac inspect. An empty or blank value reads as unset. Never holds back agac retry, which walks every file holding a record it named. |
Directory Structure
Here's where it gets interesting: Agent Actions uses a two-level structure—project-level assets shared across workflows, and workflow-level assets specific to each domain:
project/
├── agent_actions.yml # Project config
│
├── # ════════════════════════════════════════════════════════
├── # PROJECT-LEVEL (shared across all workflows)
├── # ════════════════════════════════════════════════════════
├── schema/ # Output schemas (project-level only)
├── tools/ # Custom tools (shared)
├── prompt_store/ # Shared prompt templates (optional)
│
├── # ════════════════════════════════════════════════════════
├── # WORKFLOW-LEVEL (domain-specific)
├── # ════════════════════════════════════════════════════════
└── agent_workflow/
└── my_workflow/
├── agent_config/
│ └── my_workflow.yml # Agentic workflow definition
├── agent_io/
│ ├── staging/ # Input data (starting point)
│ └── target/ # Output data
├── seed_data/ # Static reference data (workflow-level)
└── prompt_store/ # Domain-specific prompts (optional)
Asset Location Summary
| Asset | Project Level | Workflow Level | Notes |
|---|---|---|---|
| Schemas | schema/ | — | Always project-level; shared across workflows |
| Tools | tools/ | — | Always project-level; shared across workflows |
| Prompts | prompt_store/ | workflow/prompt_store/ | Either or both; searched recursively |
| Seed Data | — | workflow/seed_data/ | Always workflow-level; domain-specific |
| Input/Output | — | workflow/agent_io/ | Always workflow-level |
This structure keeps your agentic workflows organized while enabling reuse. Shared schemas ensure consistent data contracts; workflow-level seed data enables domain customization without touching shared assets.
See Also
- Defaults — Configuration inheritance system
- Templates — Template-based configuration
- Run Modes — Batch vs online execution
- Granularity — Record vs file processing