Skip to content

feat: agent configs can be YAML or TOML files (1.11.0) - #192

Merged
PaulAsjes merged 5 commits into
mainfrom
feat/yaml-toml-agent-configs
Nov 12, 2026
Merged

PaulAsjes merged 5 commits into
mainfrom
feat/yaml-toml-agent-configs

Conversation

@PaulAsjes

Copy link
Copy Markdown
Collaborator

Summary

Agent configs could only be saved as JSON, which is hard to read and edit by hand for configs this deeply nested. A config file's extension now sets its format, so agent_configs/ can hold .json, .yaml/.yml or .toml files, and agents add and agents pull take --config-format to pick the format of new files.

Details
  • Where the format comes from: the extension of the config path in agents.json (or tools.json, tests.json). Anything that isn't .yaml/.yml/.toml is read as JSON, so existing projects behave exactly as before. The index files themselves stay JSON.
  • Which commands it reaches: every config read and write goes through project::read_value / write_config_in_project, so push, status, test, graph, workflow diagram and the tool and test commands all handle the three formats. write_json_in_project is renamed to write_config_in_project to match.
  • --config-format (json, yaml, toml):
    • On pull, it applies to new files only. Existing files keep their format, and a new branch file follows its agent's config unless the flag says otherwise.
    • On add, it defaults to the format of --from-file, then JSON. It conflicts with --output-path, whose extension decides.
  • add converts before it creates: the config is rendered before the agent is created, so a config the format can't hold doesn't leave a remote agent with no local file.
  • TOML has no null, so writing TOML drops null fields and null array elements. Agents lose nothing: push sends a PATCH, where a missing field is left alone, and a field that pulled as null was unset already. The gap is that a TOML config can't clear a field, because deleting its line leaves the remote value as it is; that needs null in JSON or YAML. Tests are updated with a PUT, so a TOML test config relies on the server treating null and missing the same.
  • TOML layout: objects become [sections] and arrays of objects [[sections]]; parents that hold only subtables print no header, and empty objects keep theirs so they survive a round trip. Multi-line prompts come out as """ strings.
  • Rejected values: integers above i64::MAX are an error rather than a lossy float, and TOML nan/inf can't be read. TOML datetimes read as strings.
  • Libraries: uses serde_yaml and toml_edit, both already dependencies, so Cargo.lock only changes for the version bump.
  • Not included: --format toml for API command output. src/formatter.rs is generated by Fern and not in .fernignore, so that change belongs in the generator; we'll ask Fern if people want it. tests push auto-discovery still only scans .json files.
  • Bumps the version to 1.11.0, since this adds behavior and main is at 1.10.0.

Testing

  • cargo test: everything passes (2155 lib, 265 workflow unit, 875 wire).
    • 8 new unit tests in config_format.rs:
      • the format follows the extension (unknown or no extension stays JSON)
      • JSON, YAML and TOML round-trip a nested config losslessly
      • TOML section layout, empty objects kept
      • nulls dropped
      • values TOML can't hold rejected
      • datetimes read as strings
      • parse errors reported
    • 4 new integration tests in tests/agents_config_format_test.rs, run against a mock API:
      • pull --config-format toml writes a .toml config without nulls, and push PATCHes the same fields back
      • pull keeps an existing .yaml file's format despite --config-format toml
      • add --from-file support.yml creates a YAML config and sends the file's fields
      • a broken .toml file reports "Invalid TOML"
  • cargo clippy --all-targets: no warnings in the changed code.
  • Not run against the live API.

🤖 Generated with Claude Code

A config file's extension now sets its format: .json, .yaml/.yml or
.toml. Index files stay JSON and their config paths can point at any of
the three. `agents add` and `agents pull` take --config-format for new
files; existing files keep their format, a new branch file follows its
agent's, and `add --from-file` follows the file it read.

TOML has no null, so writing TOML drops null fields. Agents lose nothing,
since push PATCHes, but a TOML config cannot clear a field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@PaulAsjes
PaulAsjes marked this pull request as ready for review November 12, 2026 10:53
@PaulAsjes
PaulAsjes requested review from bitpshr and a balanced review from Copilot November 12, 2026 11:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

TOML conversion silently drops runtime nulls and can erase objects, while branch pulls can replace registered config paths and leave stale files.

3 open issues
What changed in this PR

Adds YAML and TOML support to the CLI’s local configuration workflow, while keeping registry files in JSON and preserving JSON as the default.

Changes:

  • Selects config parsing and serialization by file extension across agent, tool, and test workflows.
  • Adds --config-format to agent creation and pull commands, with conversion checks before remote creation.
  • Adds format-conversion tests and documentation, and bumps the version to 1.11.0.
File Description
tests/​agents_config_format_test.rs Adds integration coverage for format selection, synchronization, and parse errors.
README.md Documents supported formats, CLI flags, and TOML limitations.
cli/​elevenlabs/​workflow/​tools.rs Uses format-aware config writes for tools.
cli/​elevenlabs/​workflow/​tests.rs Uses format-aware config writes for tests.
cli/​elevenlabs/​workflow/​project.rs Centralizes extension-based config reading and writing.
cli/​elevenlabs/​workflow/​mod.rs Registers the config-format module.
cli/​elevenlabs/​workflow/​config_format.rs Implements JSON, YAML, and TOML conversion with unit tests.
cli/​elevenlabs/​workflow/​agents.rs Adds format selection for agent and branch configs.
Cargo.toml Bumps the package version to 1.11.0.
Cargo.lock Updates the locked package version to 1.11.0.

Review effort: Balanced

Comment thread cli/elevenlabs/workflow/agents.rs Resolved
…rays

- An object whose fields are all null rendered as an implicit, empty
  table and vanished from the TOML file. Decide the header from the
  filled table, so it round-trips as {}.
- A null array element is data (a tool's constant value, say), not an
  unset field, so dropping it changed what push sends. Writing TOML now
  refuses, naming the field and pointing at JSON or YAML.
- `pull --branch` always made a new branch file, leaving the registered
  one stale and, with --config-format, switching its format. It now
  reuses the file registered under that branch's name or ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Configuration conversion silently drops nulls from literal JSON constants and converts non-finite YAML numbers to null, allowing pushes to corrupt tool arguments or clear settings.

1 open issue
3 resolved since last review

Review effort: Balanced

…null

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

TOML conversion silently drops null members from literal JSON payloads, so a round trip followed by a push changes the tool’s configured payload.

No open issues 🎉

2 previously missed issues

In code that hasn't changed since last review

High severity Preserve nulls in literal JSON payloads during TOML conversion

cli/​elevenlabs/​workflow/​config_format.rs:149

Null members can be literal payload data: ObjectJsonSchemaPropertyInput::constant_value accepts arbitrary JSON, so {"key": null} must not become {}. This recursion silently drops those members, including in all-object arrays such as [{"key": null}], and a subsequent push changes the tool's configured payload. Reject nulls in literal-data subtrees with a JSON/YAML recommendation, or restrict omission to schema-known optional configuration fields.

Medium severity Persist successful agent registrations when a later conversion fails

cli/​elevenlabs/​workflow/​agents.rs:1106

When a multi-agent TOML pull writes one new config and a later config contains an unsupported value such as [null], this ? exits before save_agents after the loop. The earlier file remains unregistered, and retrying generates a suffixed duplicate. Preflight conversions before writing files, or persist successful registrations before returning a conversion error, including errors from branch writes.

1 resolved since last review

Review effort: Balanced

…ble configs

A null inside constant_value, dynamic variables or a tool's schemas is part
of the value, so writing TOML now refuses it instead of dropping it. A pull
that can't write one config reports it, still writes and registers the
rest, and exits with an error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@PaulAsjes
PaulAsjes merged commit 959853a into main Nov 12, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants