Hooks
Hooks are extension points where user-defined or plugin-defined code runs in response to events. They are configured in ~/.lash/config or registered by plugins at runtime.
Hook Modes
Section titled “Hook Modes”| Mode | Description |
|---|---|
observe | Fire-and-forget. Cannot alter behavior. |
blocking | Hook can modify or cancel the action. Must respond within timeout (default 5s). |
fire_and_forget | Alias for observe. |
async_apply | Non-blocking. Result applied when it arrives asynchronously. |
Plugins declare mode per-hook via hook_config in the handshake. Events listed only in hooks without hook_config default to blocking.
Hook Config Fields
Section titled “Hook Config Fields”| Field | Type | Description |
|---|---|---|
event | string | Hook event name. |
keys | string[] | (Optional, input.key only) Which keys to intercept; omit for all. |
mode | string | "blocking" (default), "fire_and_forget", or "async_apply". |
Backend Hooks
Section titled “Backend Hooks”| Hook | Description |
|---|---|
process.pre_spawn | Before process creation. |
process.post_spawn | After process starts (PID available). |
process.pre_exit | Before exit code is delivered. |
session.connect | Frontend connects. |
session.disconnect | Frontend disconnects. |
pipeline.pre_execute | Before pipeline execution. |
pipeline.post_execute | After pipeline completes (exit code, duration). |
variable.set | Variable assigned. |
variable.drop | Variable dropped. |
job.background | Job moves to background. |
job.foreground | Job moves to foreground. |
config.change | Configuration modified at runtime. |
env.change | Environment variable set or unset. |
file.redirect | File write via > or >>. |
completion.request | Tab completion requested. |
error.dispatch | Before sending error to frontend. |
plugin.describe | Plugin self-description request. |
Frontend Hooks
Section titled “Frontend Hooks”| Hook | Description |
|---|---|
display.mode_switch | Process switches between stream and TUI. |
input.pre_execute | User presses enter, before sending to backend. |
input.post_complete | After tab completion resolves. |
input.submit | Before processing user input (can deny/modify/allow). |
input.prefix | First character typed on empty buffer. |
input.key | Key press event, filtered by declared keys. |
prompt.render | Before prompt rendering. |
key.tab | Tab key pressed. |
key.up | Up arrow pressed. |
key.down | Down arrow pressed. |
Plugin Lifecycle Hooks
Section titled “Plugin Lifecycle Hooks”| Hook | Description |
|---|---|
plugin.load | Plugin process starts. |
plugin.unload | Plugin process exits. |
plugin.message | Plugin sends a message. |
Hook Context
Section titled “Hook Context”Each hook receives a JSON object:
{ "event": "process.pre_spawn", "timestamp": "2026-02-28T14:30:00Z", "session_id": "abc123", "role": "user", "data": { "command": "curl", "args": ["-s", "https://example.com"], "env": { "LASH_DISPLAY": "stream,tui" } }}Hook Responses
Section titled “Hook Responses”| Action | Effect |
|---|---|
allow | Continue without modification. |
deny | Block the action (blocking hooks only). Optional reason field. |
modify | Replace data with values from data field. |
Multiple hooks per point are comma-separated. Execution order matches declaration order. Blocking hooks chain — each receives the output of the previous.
Configuration
Section titled “Configuration”In ~/.lash/config:
[hooks]process.pre_spawn = observe:/usr/local/bin/log-commandsinput.pre_execute = blocking:~/.lash/plugins/linterprompt.render = fire_and_forget:~/.lash/plugins/loggerValid type prefixes: observe, blocking, fire_and_forget, async_apply.
Key Event Hooks (input.key)
Section titled “Key Event Hooks (input.key)”Plugins register for specific keys via input.key in hook_config. The daemon only dispatches events for keys with registered hooks, avoiding unnecessary round-trips on every keystroke.
Setup flow:
- After frontend connects, daemon collects all hooked key names.
- Daemon sends
KeyHookConfigmessage to frontend. - Frontend only sends
KeyEventfor hooked keys. - Daemon dispatches to entries whose
keyslist includes the pressed key.
Key naming convention:
| Category | Examples |
|---|---|
| Printable | ">", "a", "/", " " |
| Control | "ctrl+a" .. "ctrl+z" |
| Navigation | "up", "down", "left", "right", "home", "end" |
| Special | "enter", "tab", "backspace", "escape", "delete", "shift+tab" |
| Modified | "ctrl+left", "ctrl+right" |
Prefix Hooks (input.prefix)
Section titled “Prefix Hooks (input.prefix)”The input.prefix hook fires on the first character typed on an empty buffer. A deny response with prefill in data causes the line editor to return the prefilled text.
Shared Mode State
Section titled “Shared Mode State”Hooks may set a mode field on the session by including "mode": "<value>" in response data. This mode is stored in the session context, passed to subsequent hooks, and used by prompt plugins for visual changes. Setting "mode": "" clears the mode.