Problem
External tools that integrate with docker-agent (terminal emulators, IDEs, audit/observability sidecars) need to install user-level lifecycle hooks (session_start / stop / permission_request / ...). Today the only user-level install point is the hooks: block in ~/.config/cagent/config.yaml, which means:
- installers must parse and rewrite a user-owned YAML file in place (fragile: comments, formatting, and ordering are easily clobbered)
- clean uninstall requires marker-block surgery
- two tools editing the same block can conflict
Proposal
- Hooks drop-in directory: load
<config-dir>/hooks.d/*.yaml, where each file is a standalone HooksConfig (same schema as the userconfig hooks: block).
- Files loaded in lexicographic order
- Merged additively after the userconfig
hooks: block and before agent-config and CLI hooks (same merge path as runConfig.GlobalHooks)
- Malformed files: log a warning and skip — a broken drop-in never breaks a run
- Install = write one self-contained file; uninstall = delete it; no shared-file edits
- Config-dir env override: support
DOCKER_AGENT_CONFIG_DIR (plus CAGENT_CONFIG_DIR alias, matching the existing dual-env convention used for the models gateway) as a fallback when --config-dir is not passed. Precedence: flag > env > default. External tools need this to locate hooks.d under non-default config dirs, mirroring conventions like CODEX_HOME / OPENCODE_CONFIG_DIR.
Motivating example
Terminal integrations à la cmux: show agent running/idle state in the sidebar, surface tool-permission approvals as actionable cards, notify when the model stops, and restore agent sessions across app relaunches. cmux integrates Codex/Gemini/Copilot/Hermes by writing hook entries into each agent's config file; a drop-in directory gives docker-agent the cleanest possible equivalent — one cmux-owned file, trivially uninstallable. The same mechanism serves any other integrator.
Non-goals
- No agent-schema change (userconfig only; frozen config versions untouched)
- No change to hook semantics or existing merge precedence
Happy to send a PR — the loading/merge change is small and additive, with tests pinning lexicographic order, additive merge, and warn-and-skip behavior.
Problem
External tools that integrate with docker-agent (terminal emulators, IDEs, audit/observability sidecars) need to install user-level lifecycle hooks (
session_start/stop/permission_request/ ...). Today the only user-level install point is thehooks:block in~/.config/cagent/config.yaml, which means:Proposal
<config-dir>/hooks.d/*.yaml, where each file is a standaloneHooksConfig(same schema as the userconfighooks:block).hooks:block and before agent-config and CLI hooks (same merge path asrunConfig.GlobalHooks)DOCKER_AGENT_CONFIG_DIR(plusCAGENT_CONFIG_DIRalias, matching the existing dual-env convention used for the models gateway) as a fallback when--config-diris not passed. Precedence: flag > env > default. External tools need this to locatehooks.dunder non-default config dirs, mirroring conventions likeCODEX_HOME/OPENCODE_CONFIG_DIR.Motivating example
Terminal integrations à la cmux: show agent running/idle state in the sidebar, surface tool-permission approvals as actionable cards, notify when the model stops, and restore agent sessions across app relaunches. cmux integrates Codex/Gemini/Copilot/Hermes by writing hook entries into each agent's config file; a drop-in directory gives docker-agent the cleanest possible equivalent — one cmux-owned file, trivially uninstallable. The same mechanism serves any other integrator.
Non-goals
Happy to send a PR — the loading/merge change is small and additive, with tests pinning lexicographic order, additive merge, and warn-and-skip behavior.