Documentation
¶
Overview ¶
Package agenthooks holds the committed agent-hook vocabulary: which events each coding agent has, the exact command string a hook entry carries, and how to recognise one that is already ours.
It exists because two callers must agree on those strings byte for byte. `baum setup` rewrites the hooks in a checkout it is standing in (hosted/baumcli), and the hosted service's onboarding pull request writes the same files into a repository nobody has checked out. A repository set up either way has to end up with identical files, or the two paths would fight over the same lines forever.
Customer repositories keep these command strings in tracked files, so they are frozen once they land: change what a hook *does* in the binary, not in the string that invokes it. The strings run baum only when `baum hooks agent --check` succeeds, which it does only where the hosted service was opted in to: a login, a set-up clone, or, for a baum built or installed for the hosted service, a repository whose committed settings carry these strings. Everyone else runs Entire directly, as if baum were not installed.
Index ¶
- Constants
- func ContainsDispatcher(contents []byte) bool
- func ContainsOwnedCommand(contents []byte) bool
- func Dispatcher(spec Spec, event string) string
- func EncodeJSON(value any) ([]byte, error)
- func EntireCommand(spec Spec, event string) string
- func HandlesEvent(contents []byte, spec Spec, event string) bool
- func MissingEntireNotice(spec Spec, event string) string
- func OwnCommands(contents []byte) ([]byte, error)
- func RecordOnly(agent, event string) bool
- func UserDispatcher(spec Spec, event string) string
- func Validate(agent, event string) error
- func ValidateUserWide(agent, event string) error
- type Placement
- type Spec
- type UserWide
Constants ¶
const EntireVersion = "0.11.2"
EntireVersion is the Entire CLI release baum pins. Everything derived from an Entire artifact — the installed binary, the captured onboarding templates — is keyed to it, so a bump is a deliberate act with tests to match rather than a silent drift.
const ( // SessionStartEvent is the one event that does more than delegate: it runs // the bootstrap first and reports the install notice when Entire is absent. SessionStartEvent = "session-start" )
Variables ¶
This section is empty.
Functions ¶
func ContainsDispatcher ¶
ContainsDispatcher reports whether a settings file carries at least one command that dispatches through baum, as the onboarding pull request and `baum setup` write it. Entire's own command does not count: it does not run baum.
func ContainsOwnedCommand ¶
ContainsOwnedCommand reports whether a settings file already carries at least one hook command baum recognises. Presence of the file is not enough: a repository's own `.cursor/hooks.json` is not a set-up agent.
func Dispatcher ¶
Dispatcher renders the committed hook command for one agent event. Customer repositories keep these strings forever, so the dispatcher stays a thin chain: baum when it understands the event, Entire when it does not, and today's notice or no-op when neither is installed. Its tail is Entire's own command verbatim, which is what setup replaces.
func EncodeJSON ¶
EncodeJSON encodes without Go's HTML escaping, which would otherwise replace the shell redirections in a dispatcher command with > sequences.
func EntireCommand ¶
EntireCommand renders the command `entire enable` writes for one agent event, wrapper and all. Setup replaces exactly this string, so it is also what a recognition test builds to prove the match.
func HandlesEvent ¶
HandlesEvent reports whether a project's agent hook file runs Entire for this agent event: Entire's own command and baum's committed dispatcher end in `entire hooks AGENT EVENT`, and so does a command a repository wrapped in work of its own. The text is searched rather than parsed so that a JSON file and a TOML file are read alike, and an unreadable file still counts.
func MissingEntireNotice ¶
MissingEntireNotice renders the payload an agent hook prints when Entire is not installed, matching what the committed dispatcher prints on its own when baum is missing too.
func OwnCommands ¶
OwnCommands replaces recognised Entire hook commands in place and drops every later hook entry for the same agent event and tool matcher. Editing the JSON text rather than re-encoding a decoded document keeps every unrelated key, ordering, and formatting choice the agents wrote.
The repeat copies exist because Entire recognises only its own wrapper: once a command dispatches through baum, `entire enable` or `entire agent add` appends a fresh hook beside it rather than seeing the event as handled. Copies with the same matcher would run the event twice, so the first stays and the rest go, whether they are Entire's command or a dispatcher.
func RecordOnly ¶
RecordOnly reports whether a user-wide hook's event is one baum only records (Placement.RecordOnly).
func UserDispatcher ¶
UserDispatcher renders the hook command baum installs in an agent's marketplace plugin for one event. Like the committed Dispatcher it runs baum only when `--check` succeeds, but with `--user`, and it never falls through to Entire: a repository whose own settings run Entire for the event already gets it from them, and one without them never asked for it. Without baum, or with a baum too old to know `--user`, it does nothing. The run carries `--user` too, so a hook admitted only because the user has a baum daemon records its event and runs no Entire.
Agents remember a user's trust in a hook by the exact command (Codex), so keep this string stable and change what the hook does in the binary.
func ValidateUserWide ¶
ValidateUserWide is Validate for a user-wide hook, which runs the record-only events too.
Types ¶
type Placement ¶
type Placement struct {
Event string
HookEvent string
Matcher *string
Timeout int
// Async runs the hook in the background (Claude Code's "async"), so a
// hook that fires on every tool call never makes the agent wait for it.
Async bool
// RecordOnly is an event Entire has no hook for, which only the daemon
// reads (a live session waiting on its user, or working again): baum
// records it and never hands it to Entire. No committed hook file
// carries one, so the committed vocabulary and the hosted onboarding
// stay as they are.
RecordOnly bool
}
Placement says where the user-wide hook for one event goes in an agent's settings: the agent's own hook event, the tool matcher of its group and the handler timeout in seconds. A nil Matcher writes no matcher key; zero Timeout writes no timeout. For Entire's events they mirror what `entire enable` writes for the pinned release (the onboarding templates hold a captured copy).
func UserWidePlacement ¶
UserWidePlacement returns the placement of an agent's user-wide hook for an event.
type Spec ¶
Spec describes the hook surface baum owns for one coding agent: the events Entire accepts, the committed file holding the dispatcher commands, and the system message session start reports when Entire is missing. An empty MissingNote means that agent's session start stays silent.
func OwnedCommand ¶
OwnedCommand reports the agent event a hook command runs, matching only Entire's own generated command and the dispatcher baum writes in its place, so setup and onboarding replace it rather than adding a second hook. A repository that wraps a hook in work of its own does not match: rewriting it to the bare dispatcher would silently drop that work, so setup leaves such an entry alone even though it does mention `entire hooks`.
type UserWide ¶
UserWide describes the agent events a user-scoped marketplace plugin runs, and project hook files that take precedence over those hooks.
func LookupUserWide ¶
LookupUserWide returns an agent's user-wide hook settings. Only Claude Code and Codex have them.