---
title: "Configuration-as-Code for AI Agents: YAML, TOML, and Python Config Patterns"
description: "Compare YAML, TOML, and Python-based configuration patterns for AI agents. Learn config file design, schema validation, safe loading, and default merging strategies."
canonical: https://callsphere.ai/blog/configuration-as-code-ai-agents-yaml-toml-python-patterns
category: "Learn Agentic AI"
tags: ["Configuration as Code", "AI Agents", "YAML", "TOML", "Python"]
author: "CallSphere Team"
published: 2026-03-17T00:00:00.000Z
updated: 2026-05-06T01:02:44.575Z
---

# Configuration-as-Code for AI Agents: YAML, TOML, and Python Config Patterns

> Compare YAML, TOML, and Python-based configuration patterns for AI agents. Learn config file design, schema validation, safe loading, and default merging strategies.

## Why Configuration-as-Code

Storing agent configuration in code — version-controlled config files rather than database rows or UI settings — brings the full power of software engineering to agent management. You get git history showing who changed what, pull request reviews for configuration changes, automated validation in CI, and deterministic deployments where the same commit always produces the same agent behavior.

The question is which format to use. YAML, TOML, and Python each have distinct tradeoffs for agent configuration.

## YAML Configuration

YAML is the most common format in the cloud-native ecosystem. Its strength is readability and support for complex nested structures.

```mermaid
flowchart LR
    INPUT(["User intent"])
    PARSE["Parse plus
classify"]
    PLAN["Plan and tool
selection"]
    AGENT["Agent loop
LLM plus tools"]
    GUARD{"Guardrails
and policy"}
    EXEC["Execute and
verify result"]
    OBS[("Trace and metrics")]
    OUT(["Outcome plus
next action"])
    INPUT --> PARSE --> PLAN --> AGENT --> GUARD
    GUARD -->|Pass| EXEC --> OUT
    GUARD -->|Fail| AGENT
    AGENT --> OBS
    style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
    style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
    style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
    style OUT fill:#059669,stroke:#047857,color:#fff
```

```python
# agent_config.yaml loaded by the application
YAML_EXAMPLE = """
agent:
  name: support-agent
  model: gpt-4o
  temperature: 0.7
  max_tokens: 2048
  system_prompt: |
    You are a customer support agent for Acme Corp.
    Always be polite and professional.
    If you cannot resolve an issue, escalate to a human agent.

  tools:
    - name: search_docs
      description: Search the knowledge base
      enabled: true
    - name: create_ticket
      description: Create a support ticket
      enabled: true
    - name: refund_order
      description: Process a refund
      enabled: false
      requires_approval: true

  guardrails:
    max_tool_calls_per_turn: 3
    block_pii_in_responses: true
    escalation_keywords:
      - "speak to a human"
      - "supervisor"
      - "complaint"
"""

import yaml

def load_yaml_config(path: str) -> dict:
    with open(path, "r") as f:
        config = yaml.safe_load(f)
    return config
```

The critical detail here is `yaml.safe_load`. Never use `yaml.load` with untrusted input — it can execute arbitrary Python code. `safe_load` restricts parsing to basic data types.

## TOML Configuration

TOML is more explicit than YAML and avoids its indentation pitfalls. It is the standard for Python packaging (`pyproject.toml`) and has first-class support in Python 3.11 and later via `tomllib`.

```python
TOML_EXAMPLE = """
[agent]
name = "support-agent"
model = "gpt-4o"
temperature = 0.7
max_tokens = 2048

system_prompt = '''
You are a customer support agent for Acme Corp.
Always be polite and professional.
If you cannot resolve an issue, escalate to a human agent.
'''

[guardrails]
max_tool_calls_per_turn = 3
block_pii_in_responses = true
escalation_keywords = ["speak to a human", "supervisor", "complaint"]

[[tools]]
name = "search_docs"
description = "Search the knowledge base"
enabled = true

[[tools]]
name = "create_ticket"
description = "Create a support ticket"
enabled = true
"""

try:
    import tomllib
except ImportError:
    import tomli as tomllib

def load_toml_config(path: str) -> dict:
    with open(path, "rb") as f:
        return tomllib.load(f)
```

TOML's advantage is unambiguous typing. In YAML, `yes`, `on`, `true` are all boolean true. In TOML, only `true` is boolean. This eliminates an entire class of subtle configuration bugs.

## Python Configuration

Python config files offer maximum flexibility. You get type checking, computed values, and validation built into the config definition itself.

```python
from pydantic import BaseModel, field_validator
from typing import Optional

class ToolConfig(BaseModel):
    name: str
    description: str
    enabled: bool = True
    requires_approval: bool = False

class GuardrailConfig(BaseModel):
    max_tool_calls_per_turn: int = 3
    block_pii_in_responses: bool = True
    escalation_keywords: list[str] = []

    @field_validator("max_tool_calls_per_turn")
    @classmethod
    def validate_max_calls(cls, v: int) -> int:
        if not 1  float:
        if not 0.0  dict:
    result = deepcopy(base)
    for key, value in override.items():
        if (
            key in result
            and isinstance(result[key], dict)
            and isinstance(value, dict)
        ):
            result[key] = deep_merge(result[key], value)
        else:
            result[key] = deepcopy(value)
    return result

DEFAULTS = {
    "agent": {
        "model": "gpt-4o-mini",
        "temperature": 0.7,
        "max_tokens": 1024,
    },
    "guardrails": {
        "max_tool_calls_per_turn": 3,
        "block_pii_in_responses": True,
    },
}

def load_with_defaults(config_path: str) -> dict:
    user_config = load_toml_config(config_path)
    return deep_merge(DEFAULTS, user_config)
```

## Unified Config Loader

In practice, you want a single loader that handles any format and validates the result.

```python
from pathlib import Path

class ConfigLoader:
    LOADERS = {
        ".yaml": lambda p: yaml.safe_load(open(p)),
        ".yml": lambda p: yaml.safe_load(open(p)),
        ".toml": lambda p: tomllib.load(open(p, "rb")),
        ".json": lambda p: json.load(open(p)),
    }

    @classmethod
    def load(cls, path: str) -> AgentConfig:
        p = Path(path)
        loader = cls.LOADERS.get(p.suffix)
        if not loader:
            raise ValueError(f"Unsupported config format: {p.suffix}")

        raw = loader(path)
        merged = deep_merge(DEFAULTS, raw)

        agent_data = merged.get("agent", {})
        agent_data["guardrails"] = merged.get("guardrails", {})
        agent_data["tools"] = merged.get("tools", [])

        return AgentConfig(**agent_data)
```

## Format Comparison

Use YAML when your team is already in the Kubernetes ecosystem and familiar with its conventions. Use TOML when you want strict, unambiguous typing and your config is relatively flat. Use Python configs when you need computed values, complex validation, or type safety throughout. For most AI agent projects, TOML combined with Pydantic validation offers the best balance of readability and safety.

## FAQ

### How do I handle multi-line system prompts in TOML?

TOML supports multi-line strings with triple quotes. Use single-quoted triple quotes (`'''`) for literal strings where backslashes are not interpreted as escapes. This is ideal for system prompts that may contain special characters.

### Should I validate config files in CI?

Absolutely. Add a CI step that loads every config file through your validation layer. This catches typos, invalid values, and missing required fields before they reach any environment. The validation step should take less than a second and prevents entire classes of deployment failures.

### When should I avoid configuration-as-code?

When configurations change frequently (multiple times per day) and are managed by non-technical users. In that case, a database-backed config with an admin UI is more appropriate. Configuration-as-code works best for settings that change with releases and are managed by the engineering team.

---

#ConfigurationAsCode #AIAgents #YAML #TOML #Python #AgenticAI #LearnAI #AIEngineering

---

Source: https://callsphere.ai/blog/configuration-as-code-ai-agents-yaml-toml-python-patterns
