hookconfig

package
v0.17.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 12, 2026 License: MIT Imports: 11 Imported by: 0

README

pkg/hookconfig

Owns the install/uninstall/check logic for Confab hooks in Claude Code's ~/.claude/settings.json and Codex's ~/.codex/config.toml. Provider methods (pkg/provider/{claude,codex}.go) delegate here so the provider package stays focused on paths, process detection, and rollout metadata.

OpenCode is not handled here. It has no settings/config hook system; Opencode.InstallHooks (in pkg/provider/opencode.go) writes a TS plugin to ~/.config/opencode/plugins/ directly. This package covers the two settings-file providers only.

Why a separate package

Before CF-396 (Phase 2), hook install logic lived in pkg/config (Claude side) and pkg/provider/codex.go (Codex side). Three problems pushed it out:

  1. Symmetry. Claude and Codex install logic does the same job — atomic update of a managed block in a settings file. Putting them next to each other keeps the patterns aligned.
  2. Provider methods stayed thin. With install code out of the provider package, claude.go and codex.go shrank to paths + interface methods that delegate. No 300-line install routines hiding in a "provider" file.
  3. Circular imports. pkg/provider already imports pkg/config for path constants; if pkg/config had imported pkg/provider for the hook command shape, the cycle would have blocked CF-396. Moving install logic out of pkg/config resolves that cycle once and for all.

Files

File Role
claude.go Claude Code hook install/uninstall: sync (SessionStart/SessionEnd), PreToolUse, PostToolUse, UserPromptSubmit. Each Install*/Uninstall*/Is*Installed function takes an explicit settingsPath (the provider passes p.SettingsPath()) and edits it via config.AtomicUpdateSettingsAt / config.ReadSettingsAt — so hooks install into a non-default config dir (kata hpec) without env mutation.
codex.go Codex hook install/uninstall: writes a confab-managed [features] block plus SessionStart, PreToolUse, and PostToolUse hooks in ~/.codex/config.toml. Preserves user config; atomic write with backup.

Public API

Claude
Function Purpose
InstallSyncHooks() error Install SessionStart (spawn daemon) + SessionEnd (signal shutdown) in settings.json.
UninstallSyncHooks() error Remove the two sync hooks.
IsSyncHooksInstalled() (bool, error) True iff both sync hooks are present.
InstallPreToolUseHooks() error Install bash + GitHub MCP PreToolUse interceptors for git commit / PR tracking.
UninstallPreToolUseHooks() error / IsPreToolUseHooksInstalled() (bool, error) symmetric
InstallPostToolUseHooks / Uninstall… / Is…Installed PostToolUse interceptors.
InstallUserPromptSubmitHook / Uninstall… / Is…Installed Capture user prompts.

provider.ClaudeCode.InstallHooks() calls all four install functions in sequence; UninstallHooks() mirrors that.

Codex
Function Purpose
InstallCodexHooks(configPath string) (string, error) Idempotent install of the managed block into config.toml. Returns the file path.
UninstallCodexHooks(configPath string) (string, error) Strip the managed block; restore features.hooks to its prior state.
IsCodexHooksInstalled(configPath string) (bool, error) True only when all three Confab hook events (SessionStart, PreToolUse, PostToolUse) carry a confab command. Stale single-event installs (pre-CF-492) read as "not installed" so confab setup re-emits the managed block and transparently upgrades.

The Codex managed block is delimited by # >>> confab codex hooks >>> / # <<< confab codex hooks <<< markers and installs three hook events:

  • [[hooks.SessionStart]] — daemon spawn (startup|resume|clear matcher)
  • [[hooks.PreToolUse]]Confab-Link: commit trailer + 📝 [Confab link] PR body injection (Bash matcher)
  • [[hooks.PostToolUse]] — commit/PR URL linking back to the session (Bash matcher)

Each event also writes a [hooks.state."<configPath>:<event_lower>:<group_idx>:<hook_idx>"] table with the SHA-256 trusted_hash Codex requires for non-interactive hook trust. Event labels follow Codex's snake_case convention (session_start, pre_tool_use, post_tool_use) — see codex-rs/hooks/src/lib.rs:84-110.

The hash blob covers {event_name, hooks: [{async, command, statusMessage, timeout, type}], matcher} with fields in alphabetical order. statusMessage is "Starting Confab sync" for SessionStart and "" for the tool-use events — empty-string is load-bearing because Codex's TOML Option<String> deserializes statusMessage = "" to Some(""), which canonical-JSON-serializes as "statusMessage": ""; omitting the field would round-trip to None and yield a hash mismatch.

Invariants

  • Atomic writes. Both providers use config.AtomicUpdateSettings (Claude) or a .bak + atomic rename (Codex) so a crashed install never leaves a half-edited config.
  • Idempotent. Calling Install... twice produces the same file as calling it once. Tests pin this for both providers.
  • Preserves user config. Neither provider rewrites unmanaged config. Codex only touches [features] and the managed Confab hook block.
  • No [[hooks.Stop]] / [[hooks.UserPromptSubmit]] for Codex. Codex fires Stop at every agent/turn boundary (Stop-driven shutdown would kill the root daemon prematurely), and parent-PID monitoring already covers the Claude UserPromptSubmit teleport case.
  • Trusted-hash positional keys. Codex's [hooks.state."<configPath>:<event>:<group_idx>:<hook_idx>"] key uses the hook's actual position in the existing [[hooks.<Event>]] list. countCodexHookMatcherGroups runs per event and on the post-strip config so re-installs interleave correctly with any unmanaged user-authored blocks at any of the three event types.

Dependencies

  • pkg/config — for ClaudeSettings, AtomicUpdateSettings, GetBinaryPath, tool-name constants. Codex side uses config.GetBinaryPath only.
  • pkg/logger — Claude side logs install/uninstall events.
  • github.com/pelletier/go-toml/v2 — Codex TOML parsing.

Used By

pkg/provider/claude.go and pkg/provider/codex.go (not opencode.go — it manages its own plugin file). No other package imports this directly — cmd/ routes through the Provider interface.

Documentation

Overview

Package hookconfig owns the install/uninstall/check logic for Confab hooks in Claude Code's settings.json and Codex's config.toml. Provider methods delegate here so pkg/provider doesn't carry the configuration-file detail.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func InstallCodexHooks

func InstallCodexHooks(configPath string) (string, error)

InstallCodexHooks writes the managed Confab hook block into Codex's config.toml at configPath, preserving user content and creating a backup. Returns the configPath that was written.

func InstallPostToolUseHooks

func InstallPostToolUseHooks(settingsPath string) error

InstallPostToolUseHooks installs the PostToolUse hook for GitHub link tracking.

func InstallPreToolUseHooks

func InstallPreToolUseHooks(settingsPath string) error

InstallPreToolUseHooks installs the PreToolUse hook for git commit validation. Installs with a "Bash" matcher to intercept git commits.

func InstallSyncHooks

func InstallSyncHooks(settingsPath string) error

InstallSyncHooks installs SessionStart + SessionEnd hooks for the incremental sync daemon.

func InstallUserPromptSubmitHook

func InstallUserPromptSubmitHook(settingsPath string) error

InstallUserPromptSubmitHook installs the UserPromptSubmit hook. Unlike other hooks, UserPromptSubmit doesn't use matchers.

func IsCodexHooksInstalled

func IsCodexHooksInstalled(configPath string) (bool, error)

IsCodexHooksInstalled parses configPath and returns true only when all three Confab hook events (SessionStart, PreToolUse, PostToolUse) carry a confab command. Existing SessionStart-only installs (pre-CF-492) read as "not installed" so `confab setup` re-emits the managed block and transparently upgrades them.

func IsPostToolUseHooksInstalled

func IsPostToolUseHooksInstalled(settingsPath string) (bool, error)

IsPostToolUseHooksInstalled checks if the PostToolUse hook is installed.

func IsPreToolUseHooksInstalled

func IsPreToolUseHooksInstalled(settingsPath string) (bool, error)

IsPreToolUseHooksInstalled checks if the PreToolUse hook is installed.

func IsSyncHooksInstalled

func IsSyncHooksInstalled(settingsPath string) (bool, error)

IsSyncHooksInstalled checks whether sync daemon hooks are installed. Recognizes both old ("sync start/stop") and new ("hook session-start/end").

func IsUserPromptSubmitHookInstalled

func IsUserPromptSubmitHookInstalled(settingsPath string) (bool, error)

IsUserPromptSubmitHookInstalled checks if the UserPromptSubmit hook is installed.

func UninstallCodexHooks

func UninstallCodexHooks(configPath string) (string, error)

UninstallCodexHooks removes the managed Confab hook block from Codex's config.toml, preserving the rest of the file. Returns the configPath even if no block was present.

func UninstallPostToolUseHooks

func UninstallPostToolUseHooks(settingsPath string) error

UninstallPostToolUseHooks removes the PostToolUse hook.

func UninstallPreToolUseHooks

func UninstallPreToolUseHooks(settingsPath string) error

UninstallPreToolUseHooks removes the PreToolUse hook.

func UninstallSyncHooks

func UninstallSyncHooks(settingsPath string) error

UninstallSyncHooks removes the sync daemon hooks. Handles both old ("sync start/stop") and new ("hook session-start/end") patterns.

func UninstallUserPromptSubmitHook

func UninstallUserPromptSubmitHook(settingsPath string) error

UninstallUserPromptSubmitHook removes the UserPromptSubmit hook.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL