Skip to main content

lib/skill_kit/hooks/command.ex

defmodule SkillKit.Hooks.Command do
  @moduledoc """
  Hook handler that shells out to a command.

  Exit code semantics (matching Claude Code):
  - `0` — `:ok` (allow)
  - `2` — `{:deny, output}` (block)
  - Other — `:ok` (non-blocking error)

  The hook context is passed as JSON in the `HOOK_INPUT` environment variable.
  """

  @behaviour SkillKit.Hooks.Handler

  @impl true
  def execute(%{"command" => cmd}, context) do
    input_json = Jason.encode!(context)

    case System.cmd("sh", ["-c", cmd],
           stderr_to_stdout: true,
           env: [{"HOOK_INPUT", input_json}]
         ) do
      {_output, 0} -> :ok
      {output, 2} -> {:deny, String.trim(output)}
      {_output, _code} -> :ok
    end
  end
end