Skip to content

[go-fan] Go Module Review: goccy/go-yamlΒ #55333

Description

@github-actions

🐹 Go Fan Report: goccy/go-yaml

Module Overview

github.com/goccy/go-yaml (v1.19.2) is gh-aw's sole YAML engine β€” every frontmatter
parse, workflow import merge, and .lock.yml render goes through it.

Current Usage in gh-aw

  • Files: 103 files import it directly, concentrated in pkg/workflow (compiler/YAML
    formatting), pkg/parser (frontmatter extraction, imports, error translation), and
    pkg/cli (frontmatter mutation commands).
  • Key APIs used: yaml.Unmarshal/yaml.Marshal (the vast majority of call sites, all
    into map[string]any), yaml.MarshalWithOptions + DefaultMarshalOptions
    (pkg/workflow/yaml_options.go), yaml.MapSlice/yaml.MapItem for GitHub-Actions field
    ordering (pkg/workflow/yaml.go), yaml.FormatError for translated parser errors
    (pkg/parser/yaml_error.go), and one call to yaml.DisallowUnknownField()
    (pkg/cli/env_command.go:286).
  • Not used: the AST layer (ast.File/parser.ParseBytes), yaml.CommentMap,
    yaml.Path/PathString, and the generic RegisterCustomMarshaler[T]/
    CustomUnmarshaler[T] hooks β€” everything goes through map[string]any.

Research Findings

Live upstream research was unavailable this run β€” see details

gh api calls returned 401 Bad Credentials (GH_TOKEN reported invalid by
gh auth status), and WebFetch/WebSearch permissions could not be granted in this
sandbox. Because of that, Step 3 of the standard methodology (release notes, changelog,
recent features from the module's own repository) could not be completed live β€” the
findings below come entirely from reading gh-aw's own code and its comments describing
goccy's behavior, cross-referenced against call sites.

Suggested follow-up: check why GH_TOKEN was invalid for this run β€” it silently
degrades every future Go Fan review's upstream research step, not just this one.

Improvement Opportunities

πŸƒ Quick Wins

  1. UpdateWorkflowFrontmatter (pkg/parser/workflow_update.go:47) skips a correctness
    fix applied everywhere else.
    It calls plain yaml.Marshal(frontmatter) and never
    calls parser.QuoteCronExpressions afterward. Five other call sites that marshal
    frontmatter YAML (pkg/workflow/frontmatter_extraction_yaml.go:103,
    pkg/workflow/tools.go:205,299, pkg/workflow/trigger_parser.go:932,
    pkg/cli/update_actions_content_refs.go:119) all post-process the marshaled output
    with QuoteCronExpressions to re-quote cron strings goccy emits unquoted (e.g.
    cron: 0 14 * * 1-5 instead of cron: "0 14 * * 1-5"). UpdateWorkflowFrontmatter is
    what backs gh aw mcp add (pkg/cli/mcp_add.go:295) β€” running mcp add on a workflow
    with a schedule:/cron: trigger can leave the cron expression unquoted, unlike every
    other frontmatter-rewrite path. Fix: call QuoteCronExpressions on the marshaled
    result before ReconstructWorkflowFile.
  2. Same function also drops the compiler's YAML formatting conventions β€” 2-space
    indent and literal-style multiline strings (DefaultMarshalOptions in
    pkg/workflow/yaml_options.go) aren't applied, because pkg/parser can't import
    pkg/workflow (the reverse import already exists, so importing back would cycle).
    Workflows edited via mcp add get differently-formatted YAML than ones produced by
    gh aw compile. Fix: move an equivalent []yaml.EncodeOption into pkg/parser (or
    a shared lower-level package) so both paths use the same house style.

✨ Feature Opportunities

  1. Comment/order preservation on frontmatter rewrites. Any Unmarshal β†’ mutate β†’
    Marshal round-trip through map[string]any permanently discards user-authored
    comments and re-sorts keys, since comments/order live on the YAML AST, not on decoded
    values. goccy/go-yaml's AST layer (parser.ParseBytes β†’ ast.File) exists precisely to
    allow targeted node edits without disturbing the rest of a document. gh aw mcp add is
    the concrete, user-facing case: it only needs to touch one field (tools.<id>) in an
    otherwise hand-authored file, so it's a good first candidate to prototype AST-based
    editing on.
  2. Consider making yaml.DisallowUnknownField() opt-in more broadly (or a --strict
    flag), not just in pkg/cli/env_command.go β€” typo'd frontmatter keys currently pass
    silently through every other Unmarshal call and are only caught later (if at all) by
    JSON-Schema validation.

πŸ“ Best Practice Alignment

  • pkg/parser/yaml_error.go's yaml.FormatError + translation-table pattern is already a
    good model for user-facing YAML error messages β€” worth reusing as a precedent rather
    than reinventing elsewhere.
  • pkg/parser/schema_compiler.go:normalizeForJSONSchema is a well-documented, deliberate
    workaround for two real goccy decode quirks (int64/uint64 instead of float64;
    typed []string/typed maps instead of []any/map[string]any), and deliberately avoids
    a json.Marshal/Unmarshal roundtrip for performance. No changes needed.
  • The hand-rolled yaml.MapSlice-based ordering system (OrderMapFields,
    MarshalWithFieldOrder) is the correct way to get GitHub-Actions-conventional field
    order out of this library β€” not a case of reinventing something goccy already offers.

Recommendations

  1. Fix UpdateWorkflowFrontmatter to call QuoteCronExpressions (small, low-risk, closes
    a real correctness gap on the mcp add path).
  2. Share DefaultMarshalOptions-equivalent formatting between pkg/parser and
    pkg/workflow so all frontmatter-rewrite paths are consistent.
  3. Prototype AST-based editing for gh aw mcp add's frontmatter mutation to stop
    silently discarding comments/key order.
  4. Investigate the invalid GH_TOKEN for gh api reads so future Go Fan reviews can
    research upstream live again.

Next Steps

Pick up recommendation 1 first (smallest, highest-confidence fix); 2 and 3 are larger and
worth their own design discussion before implementation.


Module summary saved to: scratchpad/mods/goccy-go-yaml.md

Generated by 🐹 Go Fan Β· claude Β· agent Β· 150.8 AIC Β· βŒ– 4.8 AIC Β· ⊞ 8.2K Β· β—·

  • expires on Aug 25, 2026, 12:21 AM UTC-08:00

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions