Skip to main content

Overview

Hooks let you run a shell command or send an HTTP request when something happens inside EnConvo, such as an agent starting, completing, failing, or using a tool. They are configured with a JSON file, so you can add notifications, logs, local automation, or integrations without building an extension.
Hooks are fire-and-forget. They run in the background and do not block EnConvo.

Config File

Create your hooks config at:
~/.enconvo/hooks.json
EnConvo also reads the legacy file at ~/.config/enconvo/hooks.json when the new file does not exist. If both files exist, ~/.enconvo/hooks.json wins. The file is checked again whenever an event fires, so you can edit hooks while EnConvo is running. No restart is required.

Manage Hooks in Settings

Open Settings → Hooks to inspect hooks from ~/.enconvo/hooks.json. The settings panel groups entries by event, lets you toggle an entry on or off, and can open the JSON file for editing. Toggling writes enabled: false or enabled: true on that hook entry without changing the command or webhook definition.

Quick Start

1

Create the hooks folder

mkdir -p ~/.enconvo
2

Create ~/.enconvo/hooks.json

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Agent status changed' >> /tmp/enconvo-hooks.log"
          }
        ]
      }
    ]
  }
}
3

Trigger an agent

Start any agent or chat command. When its status changes, EnConvo runs the configured command and appends a line to /tmp/enconvo-hooks.log.

How Hooks Work

When an event fires, EnConvo:
  1. Loads ~/.enconvo/hooks.json.
  2. Falls back to ~/.config/enconvo/hooks.json only if the new file is absent.
  3. Finds entries inside the top-level hooks object whose key matches the event name.
  4. Applies the optional matcher regex.
  5. Skips entries where enabled is false.
  6. Runs every configured hook concurrently.
Hook event names follow the Codex lifecycle set: SessionStart, UserPromptSubmit, PreToolUse, PermissionRequest, PostToolUse, and Stop. The old EnConvo event names and old flat JSON shape are still readable for existing installs, but new writes use the wrapped Codex-style format.

Configuration Reference

{
  "hooks": {
    "event_name": [
      {
        "matcher": "optional_regex_filter",
        "enabled": true,
        "hooks": [
          { "type": "command", "command": "..." },
          { "type": "http", "url": "..." }
        ]
      }
    ]
  }
}
FieldTypeRequiredDescription
hooksobjectYesEvent map keyed by event name.
event_namestringYesEvent to listen for. Use this as a key inside hooks.
matcherstringNoRegex filter. For tool events, it matches toolName, toolTitle, or path; for other events, it matches the hook event name.
enabledbooleanNoSet to false to keep the entry in config but skip execution. Defaults to true.
hooksarrayYesCommand and HTTP hooks to execute.

Command Hook

A command hook runs a shell command. EnConvo writes the event payload to the command’s stdin as JSON.
{
  "type": "command",
  "command": "bash ~/.enconvo/hooks/on-status-change.sh",
  "timeout": 30000
}
FieldTypeDefaultDescription
type"command"-Required hook type.
commandstring-Shell command to execute.
timeoutnumber30000Timeout in milliseconds.

HTTP Hook

An HTTP hook sends the event payload as the JSON request body.
{
  "type": "http",
  "url": "https://example.com/webhook",
  "method": "POST",
  "headers": {
    "Authorization": "Bearer your-token"
  },
  "timeout": 30000
}
FieldTypeDefaultDescription
type"http"-Required hook type.
urlstring-HTTP endpoint URL.
methodstring"POST"HTTP method.
headersobject{}Additional request headers.
timeoutnumber30000Timeout in milliseconds.

Event Payload

Command hooks receive this JSON on stdin. HTTP hooks receive the same JSON as the request body.
{
  "event": "UserPromptSubmit",
  "fullEvent": "event-UserPromptSubmit",
  "sourceEvent": "run_status_changed",
  "sourceFullEvent": "event-run_status_changed",
  "params": {
    "commandKey": "agent|main",
    "runStatus": "running"
  },
  "timestamp": 1742313600000
}
FieldDescription
eventShort event name.
fullEventInternal event name with the event- prefix.
sourceEventOriginal EnConvo event that produced this hook event, when the event is mapped for Codex compatibility.
sourceFullEventOriginal internal event name with the event- prefix.
paramsEvent-specific payload.
timestampUnix timestamp in milliseconds.

Available Events

EventParamsWhen
SessionStart{ command, commandKey }A new chat session is created.
UserPromptSubmit{ commandKey, runStatus, status?, sessionId? }An agent, chat, or bot run starts from user input.
PreToolUse{ toolCallId, toolName, toolTitle?, status, sessionId?, commandKey? }A tool call starts.
PermissionRequest{ toolCallId, toolName, toolTitle?, status, sessionId?, commandKey? }A tool call reaches a permission or denied state.
PostToolUse{ toolCallId, toolName, toolTitle?, status, sessionId?, commandKey? }A tool call succeeds, fails, completes, or is denied.
Stop{ commandKey, runStatus, status?, sessionId? }An agent, chat, or bot run reaches a terminal status.
Legacy EnConvo names such as run_status_changed and agent_tool_step_changed still work, so existing hook files do not need to be migrated immediately.

Recipes

macOS Notification on Agent Failure

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "STATUS=$(cat | jq -r '.params.runStatus // .params.status') && [ \"$STATUS\" = \"failed\" ] && osascript -e 'display notification \"An agent failed\" with title \"EnConvo\"'"
          }
        ]
      }
    ]
  }
}

Log Agent Status Changes

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{time: (.timestamp / 1000 | strftime(\"%Y-%m-%d %H:%M:%S\")), agent: .params.commandKey, status: (.params.runStatus // .params.status)}' >> ~/.enconvo/agent-status.log"
          }
        ]
      }
    ]
  }
}

Log Agent Tool Calls

{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.params | \"\\(.status) \\(.toolName) \\(.toolCallId)\"' >> ~/.enconvo/agent-tools.log"
          }
        ]
      }
    ]
  }
}

Send to Slack

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "http",
            "url": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
          }
        ]
      }
    ]
  }
}

Custom Script

Create a script that reads the event payload from stdin:
#!/bin/bash
# ~/.enconvo/hooks/on-status-change.sh
INPUT=$(cat)
STATUS=$(echo "$INPUT" | jq -r '.params.runStatus // .params.status')
AGENT=$(echo "$INPUT" | jq -r '.params.commandKey')

echo "[$(date)] $AGENT -> $STATUS" >> /tmp/enconvo-hooks.log

if [ "$STATUS" = "failed" ]; then
  osascript -e "display notification \"$AGENT failed\" with title \"EnConvo\""
fi
Reference it from ~/.enconvo/hooks.json:
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.enconvo/hooks/on-status-change.sh"
          }
        ]
      }
    ]
  }
}
Make the script executable:
chmod +x ~/.enconvo/hooks/on-status-change.sh

Troubleshooting

Confirm that ~/.enconvo/hooks.json is valid JSON, the top-level key matches the event name, and the command works when run manually. If you still have ~/.config/enconvo/hooks.json, remember that it is ignored when the new file exists.
Pipe a sample payload into the script:
echo '{"event":"Stop","params":{"commandKey":"agent|main","runStatus":"failed"},"timestamp":1742313600000}' | bash ~/.enconvo/hooks/on-status-change.sh
No. Hooks are fire-and-forget. If a hook fails or times out, EnConvo logs the failure and continues processing the original event.
Prefer absolute paths for scripts and binaries. Shell ~ expansion works when the command is executed through a shell, but absolute paths are easier to debug.

Agents

Learn about EnConvo agents and custom bots

Extension API Reference

Build extensions that emit or listen to events