Documentation

cockpit hooks

Generated reference for cockpit hooks, including its syntax, options, results, and constraints from the canonical cockpit CLI source.

Applies to
CLI
WindowsmacOSLinux
GuestAGI Labo member

Verified 2026-08-30 · v4.64.0

Markdown

This reference is generated from the same canonical source distributed as cockpit CLI help. See Cockpit CLI for concepts and safe operating guidance.

Cockpit Hooks run a shell action when a Cockpit lifecycle event fires. A hook is one persisted event-to-action declaration: it selects events, optionally filters their payloads, and runs either an inline script or a script file. Cockpit Hooks are separate from the agent status-report hooks installed by Cockpit.

This command family is local-only. --host is rejected because hooks register arbitrary code on the Cockpit instance that executes them.

cockpit hooks add --event task.completed --name notify-complete --run 'cockpit display --text "${COCKPIT_TASK_NAME} completed"'
cockpit hooks list [--json]
cockpit hooks get <hookId>
cockpit hooks update <hookId> --timeout 120
cockpit hooks remove <hookId>
cockpit hooks enable <hookId>
cockpit hooks disable <hookId>
cockpit hooks runs [--hook <hookId>] [--limit <n>]
cockpit hooks test <hookId> [--task <taskId>]
cockpit hooks events
cockpit hooks help

Events

Hooks can select comma-separated event names or repeat --event. Family wildcards expand when the hook is saved. Supported wildcards are task.*, ask.*, autorun.*, fleet.run.*, and app.*; hotkey is an exact event name.

Event Fires when
task.created A task is created through the UI, CLI, Autorun, Fleet, or Master Agent
task.resumed A task returns to running from waiting_confirmation, error, or completed
task.waiting A task enters waiting_confirmation
task.completed A task enters completed
task.error A task enters error
task.removed A task is removed
ask.created A task creates an Ask
ask.resolved An Ask is answered
ask.dismissed An Ask is closed without an answer
hotkey The hook's accelerator is pressed in its configured scope
autorun.triggered An Autorun schedule dispatches, whether it targets a new or existing task
fleet.run.started A Fleet Run starts
fleet.run.completed A Fleet Run reaches completed, failed, or canceled
app.ready Cockpit starts and the hooks engine is ready
app.quit Cockpit begins quitting

Task status hooks fire only for real transitions. Rewriting the same status does not run a hook, and task creation fires task.created, not task.resumed. Hooks are independent of task-status notification settings. app.quit actions are best-effort: Cockpit waits at most five seconds for all hook work and terminates remaining hook processes before quitting.

Run cockpit hooks events to inspect every registered event, its family, accepted payload roots and fields, the common envelope fields, and wildcard selectors.

Payload and environment

The action receives compact JSON version 1 on stdin. The common shape is:

{
  "event": "task.waiting",
  "version": 1,
  "firedAt": "2026-08-20T12:34:56.789Z",
  "depth": 0,
  "hook": { "id": "hk_a1b2c3d4", "name": "notify-waiting" },
  "task": {
    "id": "task_123",
    "name": "Review API",
    "status": "waiting_confirmation",
    "previousStatus": "running",
    "waitingReason": "question",
    "agentType": "codex",
    "model": "gpt-5.4",
    "effort": "high",
    "directory": "/path/to/project",
    "isAutorun": false,
    "isFleet": false,
    "isChild": false
  }
}

The full task object is the same item returned by cockpit task list, plus previousStatus, isAutorun, isFleet, and isChild. Ask events include both that task and the complete cockpit ask list item as ask; ask.resolved adds outcome, answeredBy, and answers, while ask.dismissed adds outcome: "dismissed". Other families add only their own object:

  • hotkey: hookId, accelerator, scope, selectionText, and optional selectionUnavailable
  • autorun: id, name, executionTarget, and targetTaskId
  • fleetRun: name, runId, status, and directory
  • app.*: no event-specific object

Key fields are also exposed as environment variables:

Variables Content
COCKPIT_HOOK_ID, COCKPIT_HOOK_NAME, COCKPIT_HOOK_EVENT, COCKPIT_HOOK_DEPTH Hook identity, event, and the depth forwarded to nested cockpit calls
COCKPIT_TASK_ID, COCKPIT_TASK_NAME, COCKPIT_TASK_STATUS, COCKPIT_TASK_PREV_STATUS Task identity and transition
COCKPIT_TASK_WAITING_REASON, COCKPIT_TASK_AGENT, COCKPIT_TASK_MODEL, COCKPIT_TASK_EFFORT, COCKPIT_TASK_DIRECTORY Task runtime fields
COCKPIT_TASK_IS_AUTORUN, COCKPIT_TASK_IS_FLEET, COCKPIT_TASK_IS_CHILD String booleans, true or false
COCKPIT_ASK_ID, COCKPIT_ASK_SUMMARY Ask identity and summary; structured questions, media, and answers remain in stdin JSON
COCKPIT_HOTKEY_ACCELERATOR, COCKPIT_SELECTION Hotkey accelerator and captured selection
COCKPIT_AUTORUN_ID, COCKPIT_AUTORUN_NAME, COCKPIT_AUTORUN_TARGET Autorun identity and execution target
COCKPIT_FLEET_NAME, COCKPIT_FLEET_RUN_ID, COCKPIT_FLEET_RUN_STATUS Fleet Run identity and status

For a received event at depth n, the action gets COCKPIT_HOOK_DEPTH=n+1. The CLI forwards that value when the action creates another task so downstream events retain the loop-prevention depth.

Filters

--filter <path>=<value> matches a payload field. Values support * and ? globs and can be comma-separated. Multiple filters are ANDed; values inside one filter are ORed. Booleans match true or false, and a missing or null field matches only null.

cockpit hooks add --event task.* \
  --filter 'task.name=Release *' \
  --filter 'task.model=gpt-5.*' \
  --run-file ./release-hook.sh

The path must be present in every selected event's payload specification. Task filters are valid only when every selected event is in task.* or ask.*. Named flags are aliases for the same stored path filters:

Alias Stored match
--task <taskId> task.id=<taskId>
--task-name <glob> task.name=<glob>
--agent <value>[,value...] task.agentType
--model <glob>[,glob...] task.model
--effort <value>[,value...] task.effort
--autorun / --no-autorun `task.isAutorun=true
--fleet / --no-fleet `task.isFleet=true
--child / --no-child `task.isChild=true
--created-by <value>[,value...] task.createdBy
--waiting-reason <value>[,value...] task.waitingReason
--directory <prefix> task.directory=<prefix>*

Actions and execution controls

Use exactly one action source when adding a hook:

  • --run '<script>' stores an inline, optionally multiline shell script.
  • --run-file <path> stores a script path and is preferable for long or maintained actions.

The action runs through Cockpit's login-shell resolution with the event's task directory as its working directory, the Fleet Run directory for fleet.run.*, and the home directory otherwise. --timeout <seconds> accepts 1–3600 and defaults to 60. A timeout terminates the process tree and records timedOut: true. --debounce <seconds> accepts 0–3600; repeated events for the same hook inside the window collapse to the latest event. --disabled creates or updates the hook as disabled.

Cockpit runs at most four hook actions globally. Each hook has its own FIFO queue and never runs concurrently with itself. Events at depth 3 or greater are ignored. A global circuit breaker pauses dispatch after 60 executions within 60 seconds, clears queued and debounced work, records circuitBreaker: true, and resumes on the next real task-status transition.

Hotkeys

A hotkey hook selects only the exact hotkey event and requires --accelerator. Accelerators use Electron syntax and must include Control, Alt, Command, or Meta. They cannot conflict with Cockpit's Quick Task shortcut. --scope app|global defaults to app; app scope fires while a Cockpit window is focused, while global scope registers an operating-system shortcut. --with-selection adds selected text to COCKPIT_SELECTION and hotkey.selectionText.

cockpit hooks add --event hotkey \
  --accelerator 'CommandOrControl+Shift+T' \
  --scope global \
  --with-selection \
  --run 'cockpit task run --instruction "Summarize: ${COCKPIT_SELECTION}" --directory "$HOME"'

hooks list and hooks get add registered: true|false to hotkey hooks. A false value means the accelerator is not active, including operating-system registration failures or a later Quick Task conflict.

On macOS, global selection capture saves the clipboard, sends Copy through AppleScript, reads the selection, and restores the clipboard. Grant AGI Cockpit access in System Settings > Privacy & Security > Accessibility. Without that permission, the hook still runs with an empty COCKPIT_SELECTION; its history record has selectionUnavailable: true. The first global selection hook added on macOS returns this guidance in data.notice.

Commands and JSON results

Successful control commands return {"ok":true,"data":...}. Hook definitions include id, name, events, generic filters, action, enabled, debounceMs, timestamps, and hotkey fields when applicable. The global --json flag is accepted by hooks list and the other control commands as a no-op because their output is already JSON.

Command Options data shape
cockpit hooks add --event and exactly one of --run / --run-file; filters; --name; --timeout; --debounce; --disabled; hotkey options {hook} and optional macOS notice
cockpit hooks list Optional global --json {hooks: Hook[]}
cockpit hooks get <hookId> Hook id {hook}
cockpit hooks update <hookId> Any add option; omitted fields retain their values {hook}
cockpit hooks remove <hookId> Hook id {removed: hookId}
cockpit hooks enable <hookId> Hook id {hook} with enabled: true
cockpit hooks disable <hookId> Hook id {hook} with enabled: false
cockpit hooks runs --hook <hookId>, --limit <n> {runs: HookRun[]}; default 20, maximum 200
cockpit hooks test <hookId> Optional --task <taskId> {hookId, event, result}
cockpit hooks events None {events, envelope, wildcards}
cockpit hooks help None Prints the built-in usage text

Supplying generic or named filters to update replaces the hook's user filters; omitting all filter options preserves them. Hotkey routing filters are managed automatically.

test executes the action immediately with the first expanded event selected by the hook. It bypasses normal matching, debounce, queueing, depth checks, circuit breaker accounting, and run-history persistence. For task.* and ask.*, --task selects a real task; without it Cockpit uses the first cached task, and the command fails if none exists. The returned result contains exitCode, timedOut, stdoutTail, stderrTail, and durationMs.

History and persistence

Definitions are stored separately from execution history under the Cockpit data directory's hooks/ folder: hooks.json contains only definitions, and runs.jsonl contains one execution record per line. Definitions use atomic replacement. Run records contain seq, hookId, event, taskId, startedAt, durationMs, exitCode, timedOut, and the last 4 KB each of stdout and stderr, plus circuit-breaker or selection-unavailable flags when relevant.

cockpit hooks runs returns the newest matching records in chronological order. History rotates after 2,000 lines or 2 MB by retaining the latest 1,000 lines. Removing a hook does not remove its existing run records.

Ask to Slack round trip

Use an ask.created hook to forward the complete Ask payload to Slack, then let the Slack interaction handler resolve the original Ask through the CLI:

cockpit hooks add --event ask.created --name ask-to-slack --run-file ~/.config/cockpit/ask-to-slack.sh

The script reads stdin, posts ask.summary, ask.questions, choices, descriptions, and media metadata to Slack, and associates the Slack message with ask.id. When the user clicks a Slack choice, the integration calls:

cockpit ask answer <askId> --choice "staging"

That resolves the same persistent Ask, emits ask.resolved with its answers, and resumes the originating task. If Slack should only mirror the decision, one ask.created hook is enough; add a separate ask.resolved hook when the external message also needs its final answered state.