agenthooks

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Nov 4, 2026 License: MIT Imports: 7 Imported by: 0

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

View Source
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.

View Source
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

func ContainsDispatcher(contents []byte) bool

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

func ContainsOwnedCommand(contents []byte) bool

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

func Dispatcher(spec Spec, event string) string

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

func EncodeJSON(value any) ([]byte, error)

EncodeJSON encodes without Go's HTML escaping, which would otherwise replace the shell redirections in a dispatcher command with > sequences.

func EntireCommand

func EntireCommand(spec Spec, event string) string

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

func HandlesEvent(contents []byte, spec Spec, event string) bool

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

func MissingEntireNotice(spec Spec, event string) string

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

func OwnCommands(contents []byte) ([]byte, error)

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

func RecordOnly(agent, event string) bool

RecordOnly reports whether a user-wide hook's event is one baum only records (Placement.RecordOnly).

func UserDispatcher

func UserDispatcher(spec Spec, event string) string

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 Validate

func Validate(agent, event string) error

func ValidateUserWide

func ValidateUserWide(agent, event string) error

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

func UserWidePlacement(agent, event string) (Placement, bool)

UserWidePlacement returns the placement of an agent's user-wide hook for an event.

type Spec

type Spec struct {
	Slug         string
	SettingsFile string
	Events       []string
	MissingNote  string
}

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 All

func All() []Spec

All returns every agent baum owns hooks for, in a fixed order.

func Lookup

func Lookup(agent string) (Spec, bool)

func OwnedCommand

func OwnedCommand(command string) (Spec, string, bool)

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

type UserWide struct {
	Placements   []Placement
	ProjectFiles []string
}

UserWide describes the agent events a user-scoped marketplace plugin runs, and project hook files that take precedence over those hooks.

func LookupUserWide

func LookupUserWide(agent string) (UserWide, bool)

LookupUserWide returns an agent's user-wide hook settings. Only Claude Code and Codex have them.

Jump to

Keyboard shortcuts

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