Codex.Approvals.Hook behaviour (Codex SDK v0.7.2)

Copy Markdown View Source

Behaviour for implementing pluggable approval hooks.

Hooks can provide synchronous or asynchronous approval decisions for tool invocations, command executions, and file access operations.

Callbacks

Return Values

Synchronous hooks return:

  • :allow - approve the operation
  • {:allow, opts} - approve with additional options (used by app-server approvals)
  • {:deny, reason} - deny with a reason string

Asynchronous hooks return:

  • {:async, ref} - defer decision, will call await/2 later
  • {:async, ref, metadata} - defer decision with additional metadata

{:allow, opts} supports :grant_root to grant file-change approvals for the session when requested by the app-server.

Example

defmodule MyApp.SlackApprovalHook do
  @behaviour Codex.Approvals.Hook

  @impl true
  def prepare(event, context) do
    # Add custom metadata before review
    {:ok, Map.put(context, :slack_channel, "#approvals")}
  end

  @impl true
  def review_tool(event, context, _opts) do
    # Post to Slack and return async ref
    ref = make_ref()
    MyApp.SlackClient.post_approval_request(ref, event, context)
    {:async, ref}
  end

  @impl true
  def await(ref, timeout) do
    # Wait for Slack response
    receive do
      {:approval_decision, ^ref, decision} -> {:ok, decision}
    after
      timeout -> {:error, :timeout}
    end
  end
end

Summary

Callbacks

Wait for an async approval decision.

Called before any review operation to prepare or augment context.

Review a command execution request (optional).

Review a file access request (optional).

Review a tool invocation request.

Functions

Default prepare implementation that returns the context unchanged.

Default review implementation that allows all operations.

Types

allow_opts()

@type allow_opts() :: [
  for_session: boolean(),
  execpolicy_amendment: [String.t()],
  grant_root: String.t() | Path.t()
]

async_ref()

@type async_ref() :: reference()

async_result()

@type async_result() ::
  {:async, async_ref()} | {:async, async_ref(), metadata :: map()}

context()

@type context() :: map()

decision()

@type decision() :: :allow | {:allow, allow_opts()} | {:deny, String.t() | atom()}

event()

@type event() :: map()

opts()

@type opts() :: keyword()

review_result()

@type review_result() :: decision() | async_result()

Callbacks

await(async_ref, timeout)

(optional)
@callback await(async_ref(), timeout :: pos_integer()) ::
  {:ok, decision()} | {:error, :timeout | term()}

Wait for an async approval decision.

This callback is called when a review returned {:async, ref} and the system needs to wait for the decision.

Parameters

  • ref - The reference returned by the review callback
  • timeout - Maximum time to wait in milliseconds

Returns

  • {:ok, decision} - the approval decision
  • {:error, :timeout} - timeout reached
  • {:error, reason} - other error

prepare(event, context)

(optional)
@callback prepare(event(), context()) :: {:ok, context()} | {:error, term()}

Called before any review operation to prepare or augment context.

This callback can be used to add metadata, initialize state, or transform the context before it's passed to review callbacks.

review_command(event, context, opts)

(optional)
@callback review_command(event(), context(), opts()) :: review_result()

Review a command execution request (optional).

If not implemented, commands are allowed by default.

review_file(event, context, opts)

(optional)
@callback review_file(event(), context(), opts()) :: review_result()

Review a file access request (optional).

If not implemented, file operations are allowed by default.

review_tool(event, context, opts)

@callback review_tool(event(), context(), opts()) :: review_result()

Review a tool invocation request.

Parameters

  • event - The tool call event (contains tool_name, arguments, call_id, etc.)
  • context - The approval context (thread, metadata, etc.)
  • opts - Hook-specific options

Returns

  • :allow - approve the tool invocation
  • {:deny, reason} - deny with a reason
  • {:async, ref} - defer decision, will be awaited later
  • {:async, ref, metadata} - defer with additional metadata

Functions

default_prepare(event, context)

Default prepare implementation that returns the context unchanged.

default_review(event, context, opts)

Default review implementation that allows all operations.