Skip to content

refactor(hooks/builtins): one file per builtin + simplify registration#2526

Merged
dgageot merged 3 commits intodocker:mainfrom
dgageot:board/refactor-builtins-package-one-file-per-b-e7d19d1f
Apr 27, 2026
Merged

refactor(hooks/builtins): one file per builtin + simplify registration#2526
dgageot merged 3 commits intodocker:mainfrom
dgageot:board/refactor-builtins-package-one-file-per-b-e7d19d1f

Conversation

@dgageot
Copy link
Copy Markdown
Member

@dgageot dgageot commented Apr 27, 2026

Small readability/maintainability refactor of pkg/hooks/builtins. No
public API change, no behaviour change, all existing tests pass as-is.

What changed

1. Split each builtin into its own file

builtins.go was a 130-line file mixing registration plumbing with three
unrelated builtin implementations. Now each builtin lives in its own file:

  • add_date.goAddDate constant + addDate function
  • add_environment_info.goAddEnvironmentInfo constant + addEnvironmentInfo function
  • add_prompt_files.goAddPromptFiles constant + addPromptFiles function

Each file is now fully self-contained: registered name and behaviour
sit next to each other. builtins.go keeps only the package doc and the
generic plumbing: Register, AgentDefaults, ApplyAgentDefaults, and
the small builtinHook / turnStartContext helpers.

Adding a fourth builtin is now a clear mechanical change: drop a new
add_*.go file with const + func, plus one line in Register.

2. Simplify Register and ApplyAgentDefaults

  • Register previously iterated a map[string]BuiltinFunc{...}
    and wrapped each error with fmt.Errorf("register %q builtin: %w", ...).
    The wrapping wasn't reachable in practice (RegisterBuiltin only fails
    on empty name / nil fn, neither possible with package constants), and
    map iteration is non-deterministic. Replaced with three explicit
    RegisterBuiltin calls combined via errors.Join — shorter, ordered,
    and reads top-to-bottom.

  • ApplyAgentDefaults had three near-identical 4-line struct
    literals (hooks.Hook{Type: HookTypeBuiltin, Command: ...}). A tiny
    builtinHook(name, args...) helper turns each branch into a
    one-liner, halving the function's size and aligning the three
    flag-handling branches visually.

  • Dropped the duplicated "turn_start vs session_start" rationale
    paragraph from ApplyAgentDefaults' doc — it was already in the
    package comment verbatim.

Validation

Rebased on latest origin/main. Repo-wide clean:

  • go build ./...
  • go vet ./...
  • golangci-lint run ./... → 0 issues ✅
  • go test ./... → all packages pass ✅
  • Existing pkg/hooks/builtins tests pass unchanged (no test edits
    needed — public API is identical).

Out of scope

  • AgentDefaults.IsZero() is currently only consumed by its own test.
    Left in place since it's a documented part of the public API and the
    brief said "don't remove any feature."

Assisted-By: docker-agent

@dgageot dgageot requested a review from a team as a code owner April 27, 2026 11:43
gtardif
gtardif previously approved these changes Apr 27, 2026
@dgageot dgageot force-pushed the board/refactor-builtins-package-one-file-per-b-e7d19d1f branch from aa4451e to 0c76915 Compare April 27, 2026 11:49
dgageot added 3 commits April 27, 2026 14:09
builtins.go now only holds the package doc, name constants, Register,

AgentDefaults / ApplyAgentDefaults, and the shared turnStartContext helper.

Each builtin (add_date, add_environment_info, add_prompt_files) lives in

its own file, making it easier to read, locate, and add new builtins.

Public API and behaviour are unchanged; tests pass as-is.

Assisted-By: docker-agent
- Replace the map-iteration in Register with three explicit

  RegisterBuiltin calls combined via errors.Join. The previous loop's

  per-name error wrapping wasn't reachable in practice (RegisterBuiltin

  only fails on empty name / nil fn, neither of which can occur with

  package constants and functions). errors.Join keeps registration

  order deterministic and reads top-to-bottom.

- Add a tiny builtinHook helper so each ApplyAgentDefaults branch is a

  one-liner instead of a four-line struct literal.

- Drop the duplicated turn_start vs session_start rationale from

  ApplyAgentDefaults' doc; it already lives verbatim in the package

  comment.

Public API and behaviour are unchanged; tests pass as-is.

Assisted-By: docker-agent
…its function

The AddDate / AddEnvironmentInfo / AddPromptFiles registered-name

constants used to live grouped in builtins.go. Move each next to its

function in the corresponding add_*.go file so each builtin is fully

self-contained: name + behaviour in one place.

builtins.go now holds only generic plumbing (Register, AgentDefaults,

ApplyAgentDefaults, builtinHook and turnStartContext helpers); adding

a new builtin is purely 'drop a new add_*.go with const + func + one

line in Register'.

Public API and behaviour are unchanged; tests pass as-is.

Assisted-By: docker-agent
@dgageot dgageot force-pushed the board/refactor-builtins-package-one-file-per-b-e7d19d1f branch from 0c76915 to 625077c Compare April 27, 2026 12:10
@dgageot dgageot merged commit 28f3b4f into docker:main Apr 27, 2026
5 checks passed
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.

2 participants