mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 20:14:50 +00:00
Input-mutation hooks should be opt-in. Adds an explicit YAML toggle so
operators turn them on after verifying the regex / policy matches their
content, instead of getting silent mutation on first install.
- internal/hooks/builtin/loader.go: Spec.DefaultDisabled (yaml
default_disabled). Reverse-named so zero value preserves prior
default-on behavior for any spec that omits the field.
- internal/hooks/builtin/seed.go:
- Fresh insert path honors the flag → row created with enabled=false
- Version-bump path: when an UPDATE crosses the boundary that newly
introduces default_disabled=true, flip enabled→false once. Subsequent
boots without a version bump leave the user's manual re-enable alone
(the switch fall-through does nothing on equal versions). Logs
hooks.builtin_default_off_applied for audit.
- internal/hooks/builtin/builtins.yaml: pii-redactor v1 → v2 with
default_disabled: true. Existing installs auto-flip to disabled on
next boot via the version-bump branch above; users re-enable through
the UI toggle when ready.
- Tests:
- TestSeed_DefaultDisabledOnFreshInsert (insert respects flag)
- TestSeed_DefaultDisabledFlipsOnVersionBump (one-shot flip + user
re-enable preserved on the next no-bump boot)
57 lines
2.7 KiB
YAML
57 lines
2.7 KiB
YAML
# GoClaw builtin hooks registry.
|
|
#
|
|
# Each entry is shipped with the binary (`//go:embed *.js`) and seeded into
|
|
# agent_hooks at startup with source='builtin' and a stable UUIDv5. Users may
|
|
# toggle `enabled` on these rows but cannot edit content — the embedded JS is
|
|
# the canonical source at every boot.
|
|
#
|
|
# Schema:
|
|
# id kebab-case stable identifier (never rename — breaks UUIDv5)
|
|
# version integer; bump to force startup overwrite of matching rows
|
|
# events list of HookEvent values (session_start, user_prompt_submit,
|
|
# pre_tool_use, post_tool_use, stop, subagent_start,
|
|
# subagent_stop). One DB row is created per event.
|
|
# scope global | tenant | agent (builtins default to global)
|
|
# matcher optional regex applied to tool_name (pre/post_tool_use only)
|
|
# if_expr optional CEL expression pre-filter
|
|
# timeout_ms per-hook wall-clock budget
|
|
# on_timeout allow | block (fail-closed for blocking events)
|
|
# priority higher = runs earlier in the chain
|
|
# mutable_fields per-hook allowlist of dotted paths the script may mutate
|
|
# via updatedInput (e.g. rawInput, toolInput.command)
|
|
# source_file name of the .js file sitting next to this YAML
|
|
# description short human summary; surfaced in docs/UI
|
|
#
|
|
# Phase 04 ships this registry empty. Phase 05 adds the first exemplar
|
|
# (pii-redactor). When adding a builtin, also add the .js file + remove
|
|
# the _placeholder.js once at least one real source_file exists.
|
|
builtins:
|
|
- id: pii-redactor
|
|
# v2: default_disabled introduced — one-shot auto-flips existing enabled
|
|
# rows to disabled (input-mutation opt-in policy). Bump again for any
|
|
# future content change.
|
|
version: 2
|
|
events: [user_prompt_submit, pre_tool_use]
|
|
scope: global
|
|
matcher: ""
|
|
if_expr: ""
|
|
timeout_ms: 2000
|
|
# Fail-open on timeout: missing one redaction is less harmful than
|
|
# blocking the whole conversation. Operators who want strict behavior
|
|
# can toggle the row to matcher/disabled via config.
|
|
on_timeout: allow
|
|
# High priority so the redactor runs BEFORE other hooks see raw input.
|
|
priority: 900
|
|
mutable_fields:
|
|
- rawInput
|
|
- toolInput.command
|
|
- toolInput.query
|
|
- toolInput.content
|
|
source_file: pii-redactor.js
|
|
description: "Masks email addresses and E.164-ish phone numbers in user input and common tool-input fields."
|
|
# Off by default — input mutation should be an explicit opt-in. Operators
|
|
# turn on via the UI toggle once they verify the regex behavior matches
|
|
# their tenant's content. Existing rows in the DB keep their user-set
|
|
# toggle; this only affects fresh installs / new event-row inserts.
|
|
default_disabled: true
|