Skip to content

Support HCL as an alternative agent config format#2598

Open
dgageot wants to merge 6 commits intodocker:mainfrom
dgageot:board/hcl-format-support-for-docker-agent-conf-21277b13
Open

Support HCL as an alternative agent config format#2598
dgageot wants to merge 6 commits intodocker:mainfrom
dgageot:board/hcl-format-support-for-docker-agent-conf-21277b13

Conversation

@dgageot
Copy link
Copy Markdown
Member

@dgageot dgageot commented Apr 30, 2026

Adds HCL as an alternative authoring format for agent configuration files,
alongside YAML. HCL documents are converted to YAML at load time, so the
existing schema, version dispatch, and migration chain are reused unchanged.

What it looks like

agent "root" {
  description = "An agent that talks like a pirate"
  instruction = "Always answer by talking like a pirate."
  model       = "auto"

  welcome_message = <<-EOT
  Ahoy! I be yer pirate guide, ready to set sail on the seas o' knowledge!

  What be yer quest? 🏴‍☠️
  EOT
}

Conventions:

  • Top-level keyed maps (agents, models, providers, mcps, rag) are
    written as labeled blocks: agent "root" { … }agents.root: { … }.
  • Inside an agent, command "name" { … }commands.name: { … }.
  • Toolsets use the label as the type field:
    toolset "mcp" { … }toolsets: [{ type: mcp, … }].
  • Multi-line strings use heredocs. Because HCL templates expand \${…},
    any literal \${…} in instructions must be escaped as \$\${…}.

See examples/pirate.hcl and examples/gopher.hcl — both produce
configurations byte-identical to their .yaml siblings (locked in by
TestHCLExamplesMatchYAML).

How it's wired

HCL bytes ──hcl.ToYAML──► YAML bytes ──read version──► v0…v8 parser ──migrate──► latest.Config

The HCL → YAML step happens once, before anyone looks at the version field.
Detection is by .hcl extension, with a content-sniff fallback (LooksLikeHCL)
for OCI artifacts and other sources that don't have a filename hint.

The converter is version-agnostic: it applies stable structural rules
(labeled-block → keyed map, etc.) that target the broad shape every schema
version has shared since v0. Field-level renames between versions are still
absorbed by the existing up-migrators. The blockRules table is the union of
HCL conventions across all supported versions; new entries are additive.

Drift protection

  • TestHCLExamplesMatchYAML — every .hcl example produces a config equal
    to its .yaml sibling.
  • TestHCLBlockRulesCoverSchemaMaps — walks agent-schema.json and asserts
    every top-level property of shape {additionalProperties: …} has a matching
    modeMapByLabel rule registered. Verified to fail with a clear message
    when a new keyed map is added to the schema without an HCL rule.
  • TestJsonSchemaWorksForExamples — now also validates .hcl examples
    (via the converter) against the JSON schema.

Notable design choices

  • Singular labeled blocks (agent "root", model "claude") rather than
    agents { root { … } }. Idiomatic HCL (cf. Terraform resource "type" "name") and lighter to write.
  • Toolset label = type so multiple toolset "mcp" { … } blocks aggregate
    into the YAML toolsets: list with type injected.
  • yaml.MapSlice for label-keyed outputs so agent declaration order
    is preserved through the YAML-marshal step (Agents is a slice in the
    Go config; order matters).
  • No HCL function/variable evaluation. Expressions are evaluated with an
    empty hcl.EvalContext{}, so templates can't reach out to anything.

Files

File What
pkg/config/hcl/hcl.go HCL → YAML converter
pkg/config/hcl/hcl_test.go Unit tests for the converter
pkg/config/config.go Detect HCL in Load, convert before YAML pipeline
pkg/config/resolve.go, pkg/sandbox/args.go Recognize .hcl extension
pkg/config/examples_test.go Cover .hcl examples + sibling-equivalence test
pkg/config/schema_test.go Schema validation for .hcl + drift test
examples/pirate.hcl, examples/gopher.hcl Drop-in HCL versions of existing examples

Validation

mise lint and mise test are both green. ./bin/docker-agent agent run --dry-run
loads both example HCL files successfully.

@dgageot dgageot requested a review from a team as a code owner April 30, 2026 07:21
gtardif
gtardif previously approved these changes Apr 30, 2026
rumpl
rumpl previously approved these changes Apr 30, 2026
Copy link
Copy Markdown
Member

@rumpl rumpl left a comment

Choose a reason for hiding this comment

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

This is cool

@docker-agent
Copy link
Copy Markdown

docker-agent Bot commented Apr 30, 2026

PR Review Failed — The review agent encountered an error and could not complete the review. View logs.

@dgageot dgageot force-pushed the board/hcl-format-support-for-docker-agent-conf-21277b13 branch from f4973f0 to 4648ae3 Compare April 30, 2026 10:17
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