Skip to content

fix(agents): coerce a non-string description in TOML command rendering - #3799

Open
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/toml-command-description-coercion
Open

fix(agents): coerce a non-string description in TOML command rendering#3799
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/toml-command-description-coercion

Conversation

@jawwad-ali

Copy link
Copy Markdown
Contributor

Problem

CommandRegistrar.render_toml_command passes the raw frontmatter description straight into _render_basic_toml_string, which iterates the value and calls ord() on each character. Frontmatter comes from yaml.safe_load, so description can be any YAML type:

description='ok string'  ->  description = "ok string"
description=None         ->  TypeError: 'NoneType' object is not iterable
description=42           ->  TypeError: 'int' object is not iterable
description=True         ->  TypeError: 'bool' object is not iterable
description=['a','b']    ->  description = "ab"        <- silently WRONG value

description: with no value is the easy one to hit — plain YAML for an empty field.

Format-branch asymmetry

This is the only renderer reached from register_commands' format branches that does not normalise description:

branch handling
render_yaml_command (same class, ~70 lines below) already coerces: if not isinstance(description, str): description = str(description) if description is not None else ""
render_markdown_command goes through yaml.dump, which handles any type
built-in gemini/tabnine template path (TomlIntegration._extract_description) returns "" for a non-str
render_toml_command no guard

So extension/preset commands rendered for the two TOML agents were the only ones affected.

Fix

Apply the same coercion the sibling already uses. After:

None       -> description = ""
42         -> description = "42"
True       -> description = "True"
['a','b']  -> description = "['a', 'b']"
1.5        -> description = "1.5"

Each still parses as valid TOML (asserted via tomllib.loads). String descriptions are untouched, so existing output is byte-identical.

Verification

  • test_render_toml_command_coerces_non_string_description — 4 parametrized types, asserted through tomllib.loads: all 4 fail before this change, pass after.
  • The 7 pre-existing test_render_toml_command_* tests (embedded triple quotes, multiline, control characters, backslashes, trailing backslash) all still pass — 11 passed together.
  • uvx ruff@0.15.0 check src tests clean.

AI-assisted: authored with Claude Code. I reproduced each failure mode through the real renderer on main, including the silent ['a','b'] -> "ab" mangling, and confirmed the sibling YAML branch already handled all three before mirroring it.

@jawwad-ali
jawwad-ali requested a review from mnriem as a code owner July 28, 2026 14:41
CommandRegistrar.render_toml_command passes the raw frontmatter `description`
straight into `_render_basic_toml_string`, which iterates the value and calls
ord() on each character. Frontmatter comes from yaml.safe_load, so description
can be any YAML type:

    description='ok string' -> description = "ok string"
    description=None        -> TypeError: 'NoneType' object is not iterable
    description=42          -> TypeError: 'int' object is not iterable
    description=True        -> TypeError: 'bool' object is not iterable
    description=['a','b']   -> description = "ab"     <- silently WRONG value

This is a format-branch asymmetry: it is the only renderer reached from
register_commands' format branches that does not normalise description.
render_yaml_command (same class, ~70 lines below) already does exactly
`if not isinstance(description, str): description = str(description) if
description is not None else ""`, render_markdown_command goes through
yaml.dump which handles any type, and TomlIntegration._extract_description
returns "" for a non-str. So only extension/preset commands rendered for the two
TOML agents were affected.

Apply the same coercion the sibling uses. After: None -> "", 42 -> "42",
True -> "True", ['a','b'] -> "['a', 'b']", each still valid parseable TOML.
String descriptions are untouched.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jawwad-ali
jawwad-ali force-pushed the fix/toml-command-description-coercion branch from dab4e13 to 1d95875 Compare July 28, 2026 14:57
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.

1 participant