Documentation Index
Fetch the complete documentation index at: https://mintlify.com/cad0p/pi-steering-hooks/llms.txt
Use this file to discover all available pages before exploring further.
defineConfig is the preferred way to author pi-steering configurations. It threads rule, plugin, and observer names through TypeScript generics so typos are caught at tsc --noEmit time rather than silently failing at runtime. At runtime the function does minimal work — it returns a normalized shallow copy of the input config. All the value is in the types.
Signature
DefineConfigInput fields
Plugins to register. Names must be unique across the active plugin set —
collisions log a
plugin-name-collision diagnostic. Pass plugins as as const satisfies Plugin[] to preserve literal name values for typo-checking in
disabledPlugins.User-authored rules. Added on top of
DEFAULT_RULES unless
disableDefaults: true. Use as const satisfies Rule[] on external constants
so the literal name values survive for disabledRules typo-checking and
when.happened.event narrowing.Standalone observers not tied to a plugin. Observer
name literals thread
through AllObserverNames so string references in Rule.observer are
typo-checked at compile time. Use as const satisfies Observer[] to preserve
the literal types.Rule names to disable. Typo-checked against the union of all registered rule
names: engine defaults (
DEFAULT_RULES), plugin-shipped rules, and your own
inline rules. A name not in that union is a compile-time error.Plugin names to disable. Typo-checked against the union of
DEFAULT_PLUGINS
names and any plugins passed in the plugins array. A disabled plugin
contributes nothing — no rules, predicates, trackers, or observers.When
true, drops both DEFAULT_RULES and DEFAULT_PLUGINS entirely.
Useful for isolated test harnesses or minimal configs that opt into only
their own rules. Distinct from disabledRules / disabledPlugins — this
flag is imperative (“disable the defaults”), while the lists are declarative
(“these items are disabled”).Fail-closed override policy applied to rules that don’t specify their own
noOverride field. When true (the default), override escape hatches are
blocked unless the rule explicitly sets noOverride: false. Set to false
to make all rules overridable unless they individually set noOverride: true.Strict mode. When
true (the default), any warning-class
SteeringDiagnostic produced while loading the config escalates to a thrown
error that disables the extension for the session. Set to false to fall
through to console.warn and keep the bridge running with whatever subset
loaded cleanly. Error-class diagnostics always throw regardless of this flag.Compile-time safety
defineConfig threads four name unions through TypeScript generics:
| Generic | What it constrains |
|---|---|
AllRuleNames<P, R> | disabledRules — must be a known rule name |
AllPluginNames<P> | disabledPlugins — must be a known plugin name |
AllObserverNames<P, Inline> | Rule.observer string references |
AllWrites<P, R, Inline> | when.happened.event and when.happened.since |
as const satisfies requirement
For cross-reference checking to work — observer name inference, rule name typo-checking, and when.happened.event narrowing — TypeScript must preserve the literal types of name and writes fields. The as const satisfies pattern does this. A plain type annotation widens the literals to string and silently disables all checking.
Plugin and Observer constants passed into defineConfig. Rules and observers declared inline inside the defineConfig({ rules: [...] }) call are inferred directly through the const R generic and don’t need the annotation.
Complete example
Behavior with no observers declared
When no plugins contribute observers and no inlineobservers array is passed, AllObserverNames resolves to never. Any string Rule.observer reference is then a compile-time error — fail-closed on unknown observer names. For configs that intentionally reference observers by name without registering them inline, use satisfies SteeringConfig as a fallback; you lose typo detection but regain flexibility.
Walk-up merge
defineConfig operates on a single config layer. When the loader discovers multiple .pi/steering.ts files walking up from the session cwd to $HOME, it merges layers with inner (closer to cwd) layers taking precedence on name collisions. Each layer is authored with defineConfig independently; the merging is the loader’s concern, not defineConfig’s.