Documentation
¶
Overview ¶
Package approval implements the human-in-the-loop gate (CLAUDE.md headline feature). A side-effecting tool call that policy gates pauses until a human approves or denies it. Policy evaluation is deterministic — no LLM decides whether something needs approval.
Index ¶
- type Decision
- type Gate
- func (g *Gate) Create(ctx context.Context, req Request) (storage.ApprovalRecord, bool, error)
- func (g *Gate) Get(ctx context.Context, id string) (storage.ApprovalRecord, error)
- func (g *Gate) Pending(ctx context.Context) ([]storage.ApprovalRecord, error)
- func (g *Gate) Request(ctx context.Context, req Request) (Decision, string, error)
- func (g *Gate) Required(tool, sideEffect string) bool
- func (g *Gate) Resolve(ctx context.Context, id string, approved bool, reason, by string) error
- type Notifier
- type Policy
- type Request
- type Rule
- type WebhookNotifier
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Gate ¶
type Gate struct {
// contains filtered or unexported fields
}
Gate is the human-in-the-loop approval queue. It persists pending approvals, notifies push channels, and blocks the calling (tool) goroutine until a human resolves the request via the API/CLI/web — or the run's context is cancelled.
func (*Gate) Create ¶
Create evaluates policy and, if approval is required, persists a pending approval and notifies push channels, returning the record (required=true). Unlike Request, it does NOT block — the caller (e.g. the SDK over HTTP) polls the approval's status instead. Returns required=false when policy allows the call outright.
func (*Gate) Request ¶
Request gates a side-effecting call. If approval is not required it returns an approved Decision immediately. Otherwise it persists a pending approval, notifies push channels, and BLOCKS until the request is resolved or ctx is done (run cancel / time budget). This is how a side-effecting call "pauses".
type Notifier ¶
type Notifier interface {
Notify(ctx context.Context, a storage.ApprovalRecord)
}
Notifier pushes a newly-pending approval to a channel (e.g. a webhook). The CLI and web page are pull channels and do not implement this.
type Policy ¶
type Policy struct {
// RequireFor lists match rules; a call needs approval if it matches ANY rule.
RequireFor []Rule
// DefaultSafe, when true, requires approval for ANY call with a non-empty side
// effect even if no rule matched — fail closed on side effects.
DefaultSafe bool
}
Policy is the deterministic rule set deciding which calls need approval. It mirrors the api/v1 ApprovalPolicy schema.
type Request ¶
type Request struct {
RunID string
StepIndex int32
Tool string
SideEffect string
Arguments map[string]any
}
Request describes a side-effecting tool call seeking approval.
type Rule ¶
Rule matches a tool call by exact tool name or by a side-effect glob (e.g. "*write*"). A rule with both set matches if EITHER matches.
type WebhookNotifier ¶
type WebhookNotifier struct {
// contains filtered or unexported fields
}
WebhookNotifier POSTs a JSON notification to a user-configured URL when an approval becomes pending. This is user-configured outbound network (like the OTLP endpoint) — RiskKernel calls it only because the user set the URL. It does NOT include any provider keys or secrets. See SECURITY.md.
func NewWebhookNotifier ¶
func NewWebhookNotifier(url string, log *slog.Logger) *WebhookNotifier
NewWebhookNotifier returns a notifier, or nil if url is empty (no push channel).
func (*WebhookNotifier) Notify ¶
func (w *WebhookNotifier) Notify(_ context.Context, a storage.ApprovalRecord)
Notify fires the webhook asynchronously (best-effort; failures are logged, never fatal — a flaky webhook must not wedge a governed run).