Skip to content

[Bug]: #3991 still reproduces on 0.16.2 — Claude ARGUMENT_HINTS fallback injects into a folded description scalar (wrap presets without explicit argument-hint) #4044

Description

@takaya0

Bug Description

#3991 (preset wrap composition drops core argument-hint and leaks its value into description) was closed by #3996, but on 0.16.2 the corruption still reproduces for the configuration that motivated the original report: Claude integration + a strategy: wrap preset whose description is long enough for the YAML dumper to fold it across multiple lines.

Two facts combine:

  1. The [bug-fix] Fix preset-wrap-drops-argument-hint: inherit argument-hint from core template #3996 inheritance fix is a no-op for bundled core commands. [bug-fix] Fix preset-wrap-drops-argument-hint: inherit argument-hint from core template #3996 adds argument-hint to the wrap-composition inheritance allowlist (copied from core_frontmatter when the preset frontmatter doesn't declare it). But the bundled core command templates (e.g. core_pack/commands/specify.md) declare no argument-hint frontmatter at all — for Claude the hints live in the hardcoded ARGUMENT_HINTS dict in src/specify_cli/integrations/claude/__init__.py. The docstring of agents.py::apply_argument_hint states this explicitly: "Built-in templates carry no argument-hint, so this is a no-op for the core path." So there is nothing to inherit, and the composed frontmatter reaches serialization without the key.
  2. The Claude ARGUMENT_HINTS fallback then injects by raw string insertion into already-serialized YAML. ClaudeIntegration.post_process_skill_contentinject_argument_hint inserts argument-hint: "…" directly after the first line starting with description:. With a short one-line description this happens to work (which is presumably why [bug-fix] Fix preset-wrap-drops-argument-hint: inherit argument-hint from core template #3996's regression test passes). With a description long enough that dump_frontmatter folds it into a multi-line scalar, the injected line lands inside the folded scalar.

Depending on whether the dumper quoted the scalar, the failure takes one of two forms (both reproduced on 0.16.2):

Steps to Reproduce

  1. Fresh project on 0.16.2:

    mkdir demo && cd demo && git init -q && git commit -q --allow-empty -m init
    specify init --here --integration claude --script sh --ignore-agent-tools --force
  2. Create a wrap preset whose command frontmatter declares only a long description (~150+ chars, so it folds when dumped) and strategy: wrap — no argument-hint:

    presets-src/demo-wrap/commands/speckit.specify.md

    ---
    description: "Create or update the feature specification from a natural language feature description. Also accepts an issue URL resolved via gh CLI (demo customization)."
    strategy: wrap
    ---
    
    <!-- demo preamble -->
    
    {CORE_TEMPLATE}

    plus a matching preset.yml with provides.templates: [{type: command, name: speckit.specify, file: commands/speckit.specify.md, strategy: wrap}].

  3. Apply and inspect:

    specify preset add --dev ./presets-src/demo-wrap
    head -8 .claude/skills/speckit-specify/SKILL.md
    python3 -c "import yaml; print(yaml.safe_load(open('.claude/skills/speckit-specify/SKILL.md').read().split('---')[1]))"

Expected Behavior

The composed frontmatter contains the preset's description exactly as declared, plus argument-hint: Describe the feature you want to specify as its own key (from the Claude ARGUMENT_HINTS mapping).

Actual Behavior

With the description above (plain scalar), the composed frontmatter is invalid YAML:

name: speckit-specify
description: Create or update the feature specification from a natural language feature
argument-hint: "Describe the feature you want to specify"
  description. Also accepts an issue URL resolved via gh CLI (demo customization).
yaml.parser.ParserError: while parsing a block mapping
  ...
expected <block end>, but found '<scalar>'

If the description contains a character that forces quoting (e.g. change it to ... Also accepts a GitHub issue/PR URL or #N reference resolved via gh CLI (demo).), the output parses but is silently corrupted:

description: 'Create or update the feature specification from a natural language feature
argument-hint: "Describe the feature you want to specify"
  description. Also accepts a GitHub issue/PR URL or #N reference resolved via gh
  CLI (demo).'

Parsed result: no argument-hint key; the hint line is absorbed into the description string.

Workaround

Declare the hint explicitly in the preset command frontmatter (argument-hint: "Describe the feature you want to specify"). It is then carried structurally through apply_argument_hint before serialization, and inject_argument_hint skips injection (key already present).

Specify CLI Version

0.16.2

AI Agent

Claude Code

Operating System

macOS 15 (Apple Silicon, Darwin 25.5.0)

Python Version

3.14

Additional Context

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions