Help us shape the future of Go! Take the 2026 Go Developer Survey

guard

package
v0.52.0 Latest Latest
Warning

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

Go to latest
Published: Oct 1, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Overview

Package guard keeps builds from taking the machine down. Run takes one of the machine's build slots and runs a command in a memory-capped systemd scope; Hook is the PreToolUse hook that routes build, test, lint and lab commands through it and refuses a third kind lab.

The slots are memcap's: flock files <slotDir>/<i>.lock with a <i>.holder record in memcap's format, so beekeeper and the memcap shell wrapper share them.

Index

Constants

View Source
const (
	// ExitBusy: no slot, or not enough memory for the cap, within the wait.
	ExitBusy = 75
	// ExitNotFound: the command could not be started.
	ExitNotFound = 127
)

Exit codes Run returns besides the command's own.

View Source
const (
	VerbStart = "run.start"
	VerbEnd   = "run.end"
)

The event log verbs of a capped run. Their detail is "<scope> <facts>: <command>": the scope's unit name exactly as the kernel prints it in an OOM kill's memcg path, then the slot and the cap (start) or the exit code, the duration and the cap's victims (end), then CommandHead.

View Source
const (
	ScopePrefix     = "memcap-"
	TestScopePrefix = "memcap-test-"
)

A capped run's scope is <ScopePrefix><pid>-<n>.scope in memcap.slice. A test's run (Options.Test) takes TestScopePrefix instead, so that the cap kill it provokes on purpose reads as a test kill, never as a build's.

View Source
const AskTool = "AskUserQuestion"

AskTool is Claude Code's tool that puts a question to the person and blocks the session until the person answers.

View Source
const LogPrefix = "beekeeper run: "

LogPrefix starts every line Run writes, the cap's victim line included.

View Source
const ModeAcceptEdits = "acceptEdits"

ModeAcceptEdits is the mode Claude Desktop turns a bypassPermissions session into when it imports it (claude://resume).

View Source
const PostTool = "slack_send_message"

PostTool is the suffix of the tool that posts a report: the Slack connector's slack_send_message.

View Source
const ReadsBudget = 10000

ReadsBudget bounds the context one repository's reads add to a call, in bytes.

View Source
const SendMessageTool = "SendMessage"

SendMessageTool is the tool one Claude session messages another with.

Variables

This section is empty.

Functions

func CommandHead added in v0.11.0

func CommandHead(argv []string) string

CommandHead is the command a run's events name: a shell's -c script rather than the shell (the hook wraps every build in zsh -c), on one line, at most 100 characters.

func CurrentContext added in v0.33.0

func CurrentContext(kubeconfig string) string

CurrentContext is the machine kubeconfig's current context, "" when it has none or cannot be read.

func IsTestScope added in v0.15.3

func IsTestScope(unit string) bool

IsTestScope reports whether a scope's unit name is a test run's.

func KubeGuardOff added in v0.47.0

func KubeGuardOff(production string) string

KubeGuardOff says why the kube guard is off, "" while it is on.

func MandatoryReads added in v0.32.0

func MandatoryReads(repo string, budget int) string

MandatoryReads gathers repo's instructions for an agent that did not start in it: CLAUDE.md and AGENTS.md with their @imports, .claude/rules, the hooks and permissions of .claude/settings.json, and the files these name as mandatory reading; within budget bytes, "" when the repository has none. Only regular text files inside repo are read, never a secret name; repo is a RepoRoot, its symlinks resolved.

func ParseSize

func ParseSize(s string) (int64, error)

ParseSize parses a systemd size with base-1024 suffixes into KiB.

func ParseWait

func ParseWait(s string) (time.Duration, error)

ParseWait parses a duration ("8m", "90s", "1h"); a bare number is seconds.

func RepoRoot added in v0.32.0

func RepoRoot(p string) string

RepoRoot is the top of the git repository or worktree holding p, "" when p is in none. It reads only the file system, never runs git.

func ReportCheck added in v0.27.0

func ReportCheck(input []byte, check func(string) []string) []byte

ReportCheck decides one PreToolUse event of a reporter session: a post whose message check finds wrong (post.Report) is denied, with what to fix as the reason. Any other tool passes, nil; a post without a message is denied.

func Run

func Run(o Options, argv []string) int

Run runs argv in a capped scope and returns its exit code: the command's, 128+signal when a signal ended it, ExitBusy when the wait ran out. Without a user systemd, or inside a capped scope already, it execs argv.

func RunCommand added in v0.11.0

func RunCommand(detail string) string

RunCommand is the command a run event names.

func RunScope added in v0.11.0

func RunScope(detail string) string

RunScope is the scope a run event names.

func ShellQuote

func ShellQuote(s string) string

ShellQuote quotes s for a POSIX shell as Python's shlex.quote does.

Types

type Hook

type Hook struct {
	// Self is the absolute path of the beekeeper binary a rewrite names.
	Self string
	// ConfigErr is why the configuration did not load: every Bash call is
	// refused with it, since the guards it configures cannot run.
	ConfigErr error
	// Shell is the shell a rewritten command runs in (sh -c semantics).
	Shell string
	// MaxLabs is how many kind clusters the machine runs at most; read
	// only for a command that creates one.
	MaxLabs func() int
	// Production is the installation the kube guard protects; empty, the
	// guard is off.
	Production string
	// ContextHint is how a refusal writes an installation's context
	// ("login.example.com-<installation>"); empty, "<context>".
	ContextHint string
	// Clusters lists the running kind clusters.
	Clusters func() []string
	// Leases lists the held leases.
	Leases func() []lease.Holder
	// Guide reports whether the session is the guide's, and the person the
	// guide asks; read only for an AskUserQuestion call.
	Guide func(session string) (bool, string)
	// Peer names the running CLI of a desktop session id, "" when none
	// runs; an error refuses the send. Nil passes every SendMessage.
	Peer func(host string) (string, error)
	// Project is the session's own project ($CLAUDE_PROJECT_DIR), whose
	// instructions Claude Code loads itself; "" takes the call's cwd.
	Project string
	// Reads reports whether a call is the session's first write in the
	// repository, and records it; nil adds no repository reads.
	Reads func(session, repo string) bool
	// Kubeconfig is the kubeconfig list the session's commands use by
	// default ($KUBECONFIG, else MachineKubeconfig).
	Kubeconfig string
	// MachineKubeconfig is the machine kubeconfig (~/.kube/config), which
	// keeps no current context.
	MachineKubeconfig string
	// ModelServer reads the host's model server, whose loads need its
	// lease; called only for a command that may load a model, nil guards
	// nothing.
	ModelServer func() ModelServer
}

Hook decides one PreToolUse event.

func (Hook) Decide

func (h Hook) Decide(input []byte) []byte

Decide returns the hook's JSON answer for the event, nil to let the call pass unchanged. Malformed input passes. A call the hook does not refuse that is the session's first write in another repository carries that repository's instructions as additional context.

type ModelServer added in v0.40.0

type ModelServer struct {
	// URL is ollama's API, LemonadeURL Lemonade Server's; "" guards
	// neither.
	URL         string
	LemonadeURL string
	// LabTests are the agentlab subcommands that run turns on its models.
	LabTests []string
}

ModelServer is what the hook knows of the host's model servers.

type Options

type Options struct {
	// Max is the scope's MemoryMax, a systemd size ("12G").
	Max string
	// Swap is the scope's MemorySwapMax; "0": a build does not swap.
	Swap string
	// Wait bounds the wait for a slot and for the memory the cap needs.
	Wait    time.Duration
	SlotDir string
	Slots   int
	Stderr  io.Writer
	// Record appends a run event (VerbStart, VerbEnd) to the event log; nil
	// records nothing. It must not fail or block the run: it swallows its
	// own errors and bounds its wait.
	Record func(verb, detail string)
	// Test names the scope TestScopePrefix…: a test's run, whose cap kill
	// snapshot and watch report as a test kill.
	Test bool
}

Options configure one capped run.

type ReadsMarker added in v0.32.0

type ReadsMarker struct {
	Dir string
}

ReadsMarker records which repositories a session was given, one empty file per session and repository under Dir.

func (ReadsMarker) First added in v0.32.0

func (m ReadsMarker) First(session, repo string) bool

First reports whether this is the session's first call for repo, and records it: the marker is created exclusively, so of two concurrent calls only one is first. Any error reads as not first: the reads are extra.

type Request added in v0.22.0

type Request struct {
	Event   string `json:"hook_event_name"`
	Session string `json:"session_id"`
	Mode    string `json:"permission_mode"`
	Tool    string `json:"tool_name"`
}

Request is the part of a PermissionRequest event the hook reads.

func Permission added in v0.22.0

func Permission(input []byte, started func(session string) bool) ([]byte, Request)

Permission decides one PermissionRequest event. It allows the request only when the session runs in acceptEdits and started reports it as a session beekeeper started in bypassPermissions; any other event, malformed input included, gets no decision (nil) and the person gets the normal card. started is asked only for an acceptEdits request, so every other request is decided without reading beekeeper's state.

Jump to

Keyboard shortcuts

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