Skip to content

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.

ModeDescription
observeFire-and-forget. Cannot alter behavior.
blockingHook can modify or cancel the action. Must respond within timeout (default 5s).
fire_and_forgetAlias for observe.
async_applyNon-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.

FieldTypeDescription
eventstringHook event name.
keysstring[](Optional, input.key only) Which keys to intercept; omit for all.
modestring"blocking" (default), "fire_and_forget", or "async_apply".
HookDescription
process.pre_spawnBefore process creation.
process.post_spawnAfter process starts (PID available).
process.pre_exitBefore exit code is delivered.
session.connectFrontend connects.
session.disconnectFrontend disconnects.
pipeline.pre_executeBefore pipeline execution.
pipeline.post_executeAfter pipeline completes (exit code, duration).
variable.setVariable assigned.
variable.dropVariable dropped.
job.backgroundJob moves to background.
job.foregroundJob moves to foreground.
config.changeConfiguration modified at runtime.
env.changeEnvironment variable set or unset.
file.redirectFile write via > or >>.
completion.requestTab completion requested.
error.dispatchBefore sending error to frontend.
plugin.describePlugin self-description request.
HookDescription
display.mode_switchProcess switches between stream and TUI.
input.pre_executeUser presses enter, before sending to backend.
input.post_completeAfter tab completion resolves.
input.submitBefore processing user input (can deny/modify/allow).
input.prefixFirst character typed on empty buffer.
input.keyKey press event, filtered by declared keys.
prompt.renderBefore prompt rendering.
key.tabTab key pressed.
key.upUp arrow pressed.
key.downDown arrow pressed.
HookDescription
plugin.loadPlugin process starts.
plugin.unloadPlugin process exits.
plugin.messagePlugin sends a message.

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" }
}
}
ActionEffect
allowContinue without modification.
denyBlock the action (blocking hooks only). Optional reason field.
modifyReplace 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.

In ~/.lash/config:

[hooks]
process.pre_spawn = observe:/usr/local/bin/log-commands
input.pre_execute = blocking:~/.lash/plugins/linter
prompt.render = fire_and_forget:~/.lash/plugins/logger

Valid type prefixes: observe, blocking, fire_and_forget, async_apply.

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:

  1. After frontend connects, daemon collects all hooked key names.
  2. Daemon sends KeyHookConfig message to frontend.
  3. Frontend only sends KeyEvent for hooked keys.
  4. Daemon dispatches to entries whose keys list includes the pressed key.

Key naming convention:

CategoryExamples
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"

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.

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.