Plugin System
Plugins are external processes that communicate with the backend over Unix domain sockets. They are language-agnostic, crash-isolated, and independently deployable.
Lifecycle
Section titled “Lifecycle”- Backend reads
~/.lash/plugins.confon startup. - For each plugin, spawns the process with a socket path.
- Plugin opens socket, performs handshake.
- During execution, plugin methods are dispatched over the socket.
- On shutdown, plugins receive a
terminatemessage.
Registration
Section titled “Registration”In ~/.lash/plugins.conf:
[plugins]powerline = builtin:powerlinehistory = builtin:historysession = builtin:sessioncompletions = builtin:completionshighlight = builtin:highlightfrequency = builtin:frequencybanner = builtin:bannercsv = /usr/local/bin/lash-csvyaml = ~/.lash/plugins/yaml-pluginBuilt-in plugins are spawned as lash --plugin <name> <socket-path>. External plugins are spawned directly with the socket path as the first argument.
lash --list-plugins sends plugin.describe to each plugin and displays their names, descriptions, hooks, methods, and completions.
Handshake Protocol
Section titled “Handshake Protocol”All plugin communication uses JSON lines over Unix domain socket at ~/.lash/plugins/<name>.sock.
Backend to plugin:
{"type":"handshake","version":"1.0"}Plugin to backend:
{ "type": "handshake_ok", "methods": ["csv"], "hooks": ["pipeline.post_execute", "plugin.describe"], "completions": ["kubectl"], "hook_config": [ {"event": "input.key", "keys": ["ctrl+c", "escape"], "mode": "blocking"}, {"event": "prompt.render", "mode": "fire_and_forget"} ]}| Field | Description |
|---|---|
methods | Method names the plugin provides for functional chains. |
hooks | Hook events subscribed to (default mode: blocking). |
completions | Command prefixes the plugin completes (["*"] for all). |
hook_config | (Optional) Per-event mode and key filter overrides. |
Method Call Protocol
Section titled “Method Call Protocol”Request (backend to plugin):
{"type":"call","method":"csv","args":{},"data":"name,age\nAlice,30"}Success response:
{"type":"result","data":[{"name":"Alice","age":"30"}]}Error response:
{"type":"error","problem":"CSV parse failed at row 3","suggestion":"Check for unescaped commas"}Completion Protocol
Section titled “Completion Protocol”Request:
{"type":"complete_request","text":"git ch","cursor":6,"context":{"cwd":"/home/user","env":{"PATH":"/usr/bin"},"aliases":{"ll":"ls -la"},"scope_vars":["MY_VAR"]}}Response:
{"type":"complete_response","prefix":"ch","items":["checkout","cherry-pick"]}Highlight Protocol
Section titled “Highlight Protocol”Request:
{"type":"highlight_request","text":"git commit -m 'msg'","context":{"aliases":{"ll":"ls -la"},"builtins":["exit","jobs"]}}Response:
{"type":"highlight_response","tokens":[{"offset":0,"length":3,"style":"\u001b[32m"}]}Plugin Describe
Section titled “Plugin Describe”Triggered via the plugin.describe hook:
{"type":"hook","event":"plugin.describe","session_id":"","timestamp":"...","data":{}}Response:
{"action":"modify","data":{"description":"Human-readable plugin description"}}Terminate
Section titled “Terminate”{"type":"terminate"}Priority and Conflicts
Section titled “Priority and Conflicts”Built-in methods always take priority over plugin methods. Two plugins providing the same method name is a startup error.
Crash Handling
Section titled “Crash Handling”If a plugin process dies, the backend reports it via a Problem/Suggestion error and the chain fails at the plugin method step. Plugins run as separate processes, so a crashed plugin cannot take down the shell.