Configuration
The complete configuration contract for .pi/hookit.json.
Configuration is plain JSON in .pi/hookit.json for the current project, or
~/.pi/agent/hookit.json for global policies. Project storage is only read
after Pi trusts the project. The JSON Schema at
meffmadd/HooKit/schema.json
is the validation authority: every designated JSON configuration example is
validated against it, and editors that understand JSON Schema use it for
autocompletion. Each npm release also includes that release’s unchanged
schema.json; use the bundled copy for installed-release and offline
validation. The default-branch URL can describe newer behavior. See
schema guidance.
The persisted format has a top-level object with an optional $schema, an
optional repos array, and one Section per Hook Source (local plus one
owner/repo per installed repository). Every Section maps names to Catalog
Entries, which are either a Hook or a Preset—never both.
{
"$schema": "https://raw.githubusercontent.com/meffmadd/HooKit/main/schema.json",
"repos": ["meffmadd/HooKit"],
"local": {
"no-env-access": {
"description": "Blocks reads and writes to .env files.",
"event": "tool_call",
"filter": { "toolName": "^write$", "path": "(^|/)\\.env$" },
"shell": "false"
}
},
"meffmadd/HooKit": {
"git-diff-check": {
"description": "Checks tracked changes for whitespace errors and conflict markers.",
"event": "agent_end",
"shell": "git diff --check HEAD --"
}
}
}Fields
Each config option has its own short page with an example at the top:
Storage root
| Field | Page |
|---|---|
$schema | JSON Schema reference |
repos | Available repositories |
local / owner/repo | Sections map names to Catalog Entries (local plus declared owner/repo). |
Hooks
A Hook subscribes to one Event and owns a shell decision and, optionally,
one Action. A Hook requires description and event, and at least one of
shell or action.
| Field | Page |
|---|---|
description | Human-readable summary in /hooks |
event | The Event subscribed to |
filter | Candidate criteria, ANDed |
when | Shell Precondition gating the Hook |
shell | The decision command |
action | One owned Pi Action |
default | Enabled when no enablement is saved |
Presets
A Preset is a named list of unique Hook References. It enables a set of Hooks as one unit and cannot carry any executable field.
| Field | Page |
|---|---|
description | Human-readable summary in /hooks |
preset | The Hook Reference list |
default | Enabled when no enablement is saved |
Entry identity
Each entry name is non-empty and contains neither / nor NUL. The
source-qualified identity is the Hook Reference: local/name for local
entries or owner/repo/name for repository entries. References are how
Presets name members and how reports and Filters identify a Hook, so the
restriction keeps identity unambiguous:
| Catalog Entry name | Valid? | Notes |
|---|---|---|
no-env-access | yes | ordinary local entry |
| “ (empty) | no | names are non-empty |
nested/guard | no | / is reserved for Reference separators |
nul\u0000guard | no | NUL is reserved for persisted enablement keys |
Explicitly invalid combinations
The Schema rejects combinations that cannot form a valid entry. This example
illustrates a boolean shell, which is invalid:
{
"local": {
"mistake": {
"description": "A Hook with an invalid boolean shell",
"event": "tool_call",
"shell": false
}
}
}So are an entry with neither shell nor action (inert), and an entry that
mixes a Hook’s fields with a Preset’s preset array. If a file fails
validation during loading or refresh, /hooks reports the Catalog as broken,
makes it unavailable, and clears in-memory entries and enablement. No guards
from that Catalog run until it is repaired and loaded successfully; verify
enablement afterward. By contrast, a rejected mutation leaves the caller’s
previously accepted Catalog and enablement unchanged.