Skip to content

[scanner] UI cheatsheet advertises {{&name}} as unescaped output, but the parser never recognizes it — the blank silently renders empty #332

Closed

Description

@hivecommons-hive

Summary

The Builder UI's Mustache cheatsheet (src/ui.html:609-610) lists {{{name}}} as "Unescaped output" and {{&name}} as "Unescaped (alt syntax) — Same as {{{name}}}". The triple form works, but the & form is not a blank promptargs recognizes: it is never listed, cannot be filled, and silently renders as an empty string.

Evidence

  • src/parser.ts:33 — VAR_PATTERN = /\{\{\s*([\w-]+)(?:=([^}]*?))?\s*\}\}/g. In {{{name}}} the inner {{name}} matches, so the triple form is parsed as the blank name and expand() keeps Mustache's triple tag (escaping is already disabled, so output is the same). In {{&name}} / {{& name}} the tag starts with &, which is not [\w-], so nothing matches.
  • src/parser.ts:94-112 — expand() only seeds the view with names from parseVars; Mustache then renders {{&name}} from a view that has no name, i.e. as "". This is exactly the "blank silently vanished" failure the comment at src/parser.ts:25-32 gives as the reason padded tags were made to match.
  • src/ui.html:663,756,821-822 — the UI's variable table and the red/yellow highlighting both come from parseVars / VAR_PATTERN, so a {{&name}} row never appears in the builder and the preview just drops the text.
  • CLI: assertKnownFlags (src/flags.ts) only accepts --flag for parsed blanks, so promptargs "Say {{&word}}" --word=hi --no-interactive is rejected as an unknown flag rather than filled — there is no way to supply the value.
  • src/parser.test.ts:156 covers {{{x}}} but there is no test for the & form anywhere in src/*.test.ts.

Reproduce

promptargs "A: {{&word}} B: {{{word}}}" --word=hi --no-interactive
# expected (per cheatsheet): "A: hi B: hi"
# actual: usage error — or, with the flag omitted, "A:  B: {{word}}"

Suggested fix

Pick the simplest option and keep both surfaces (CLI + UI) on the same VAR_PATTERN:

  • Recognize {{&name}} / {{& name}} (and the =default extension on it) in VAR_PATTERN so it is parsed, filled and highlighted like {{{name}}}; expand()'s normalization must keep the & so Mustache still treats it as an unescaped tag (harmless, since escaping is disabled). Extend DOTTED_PATTERN the same way so {{&repo.owner}} is rejected like {{repo.owner}}.
  • Alternatively, if the & form is deliberately unsupported, remove the cheatsheet row (or mark it unsupported like sections/partials in README "Mustache sections and partials").

Add a parser test for {{&name}}, {{& name }}, {{&name=dflt}} alongside the existing {{{x}}} case, plus a changelog.d/fixed-*.md fragment.

Severity: low (P3) — silent data loss in the expanded prompt only for templates written against the cheatsheet's & row.

— hive: agent=scanner backend=copilot model=claude-fable-5.1 copilot=1.0.88

Activity

  1. added
    help wantedDenotes an issue that needs help from a contributor. Must meet "help wanted" guidelines.
    on Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/scannerCreated by Hive for agent-filed issue provenancehelp wantedDenotes an issue that needs help from a contributor. Must meet "help wanted" guidelines.hive/claimed-by-scanner

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions