Skip to main content

Documentation Index

Fetch the complete documentation index at: https://kawax.biz/llms.txt

Use this file to discover all available pages before exploring further.

Session hooks

With hooks, you can insert logic at each stage of a Copilot session lifecycle. You can add tool execution control, audit logging, prompt enrichment, and error handling without changing core implementation.

Hook flow

Basic usage

use Revolution\Copilot\Contracts\CopilotSession;
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Types\SessionHooks;
use Revolution\Copilot\Types\Hooks\ErrorOccurredHookInput;
use Revolution\Copilot\Types\Hooks\ErrorOccurredHookOutput;
use Revolution\Copilot\Types\Hooks\PostToolUseHookInput;
use Revolution\Copilot\Types\Hooks\PostToolUseHookOutput;
use Revolution\Copilot\Types\Hooks\PreToolUseHookInput;
use Revolution\Copilot\Types\Hooks\PreToolUseHookOutput;
use Revolution\Copilot\Types\Hooks\SessionEndHookInput;
use Revolution\Copilot\Types\Hooks\SessionEndHookOutput;
use Revolution\Copilot\Types\Hooks\SessionStartHookInput;
use Revolution\Copilot\Types\Hooks\SessionStartHookOutput;
use Revolution\Copilot\Types\Hooks\UserPromptSubmittedHookInput;
use Revolution\Copilot\Types\Hooks\UserPromptSubmittedHookOutput;

Copilot::start(function (CopilotSession $session) {
    $response = $session->sendAndWait(prompt: 'Summarize the key points of this README');
    dump($response->content());
}, config: [
    'model' => 'gpt-5',
    'hooks' => new SessionHooks(
        onSessionStart: function (SessionStartHookInput $input): ?SessionStartHookOutput {
            return new SessionStartHookOutput(
                additionalContext: "Project root: {$input->cwd}",
            );
        },

        onUserPromptSubmitted: function (UserPromptSubmittedHookInput $input): ?UserPromptSubmittedHookOutput {
            if (str_starts_with($input->prompt, '/fix')) {
                return new UserPromptSubmittedHookOutput(
                    modifiedPrompt: 'Fix the current error and summarize what changed.',
                );
            }

            return null;
        },

        onPreToolUse: function (PreToolUseHookInput $input): ?PreToolUseHookOutput {
            $blocked = ['bash', 'shell', 'delete_file'];

            if (in_array($input->toolName, $blocked, true)) {
                return new PreToolUseHookOutput(
                    permissionDecision: 'deny',
                    permissionDecisionReason: "{$input->toolName} is not allowed in this environment",
                );
            }

            return new PreToolUseHookOutput(permissionDecision: 'allow');
        },

        onPostToolUse: function (PostToolUseHookInput $input): ?PostToolUseHookOutput {
            if ($input->toolName === 'read_file') {
                return new PostToolUseHookOutput(
                    additionalContext: 'If needed, explore related files and compare them.',
                );
            }

            return null;
        },

        onErrorOccurred: function (ErrorOccurredHookInput $input): ?ErrorOccurredHookOutput {
            if ($input->errorContext === 'model_call' && $input->recoverable) {
                return new ErrorOccurredHookOutput(
                    errorHandling: 'retry',
                    retryCount: 2,
                    userNotification: 'Retrying due to a temporary model error.',
                );
            }

            return null;
        },

        onSessionEnd: function (SessionEndHookInput $input): ?SessionEndHookOutput {
            if ($input->reason !== 'complete') {
                return new SessionEndHookOutput(
                    sessionSummary: "Session ended with reason: {$input->reason}",
                );
            }

            return null;
        },
    ),
]);

Available hooks

HookTrigger timingPrimary use
onSessionStartSession start (new / resume / startup)Inject initial context, override config
onUserPromptSubmittedUser prompt submissionPrompt enrichment, template expansion, input filtering
onPreToolUseBefore tool executionAllow/deny/ask, modify args, suppress output
onPostToolUseAfter tool executionModify result, mask secrets, audit logging
onErrorOccurredError inside sessionRetry, notify user, classify errors
onSessionEndSession endCleanup, metrics, summary
Returning null keeps default behavior.

Typical use cases

1) Permission control

  • Use onPreToolUse with allow-list policies.
  • Require human approval for destructive actions with permissionDecision: 'ask'.
  • Use permissionDecisionReason for explicit denial reasons.
  • See Tools for tool name candidates such as view, glob, and bash.

2) Auditing and compliance

  • Combine lifecycle hooks to collect audit events.
  • Persist collected records by session ID.

3) Prompt enrichment

  • Add project context in onSessionStart (language, framework, conventions).
  • Expand shortcuts such as /fix and /test in onUserPromptSubmitted.

4) Result filtering

  • Mask API keys, tokens, and passwords in onPostToolUse.
  • Summarize oversized results and return details only when needed.

5) Error recovery

  • Retry only when errorContext is model_call and recoverable=true.
  • Provide concise user notifications for non-recoverable paths.

6) Session metrics

  • Record start time in onSessionStart.
  • Update counters in onPreToolUse and onUserPromptSubmitted.
  • Emit duration, tool counts, and termination reason in onSessionEnd.

Hook input and output types

Common input (BaseHookInput)

PropertyTypeDescription
timestampintHook timestamp (Unix ms)
cwdstringCurrent working directory

PreToolUseHookInput

PropertyTypeDescription
toolNamestringTool name to execute
toolArgsmixedPlanned tool arguments

PreToolUseHookOutput

PropertyTypeDescription
permissionDecision?stringallow / deny / ask
permissionDecisionReason?stringReason for deny/ask
modifiedArgsmixedOverridden tool arguments
additionalContext?stringAdditional context
suppressOutput?boolSuppress tool output

PostToolUseHookInput

PropertyTypeDescription
toolNamestringExecuted tool name
toolArgsmixedRuntime tool arguments
toolResultToolResultObject|arrayTool result

PostToolUseHookOutput

PropertyTypeDescription
modifiedResultToolResultObject|array|nullModified result
additionalContext?stringAdditional context
suppressOutput?boolSuppress result output

UserPromptSubmittedHookInput

PropertyTypeDescription
promptstringUser prompt

UserPromptSubmittedHookOutput

PropertyTypeDescription
modifiedPrompt?stringModified prompt
additionalContext?stringAdditional context
suppressOutput?boolSuppress response output

SessionStartHookInput

PropertyTypeDescription
sourcestringstartup / resume / new
initialPrompt?stringInitial prompt

SessionStartHookOutput

PropertyTypeDescription
additionalContext?stringInitial session context
modifiedConfig?arrayPartial session config override

SessionEndHookInput

PropertyTypeDescription
reasonstringcomplete / error / abort / timeout / user_exit
finalMessage?stringFinal message
error?stringFinal error

SessionEndHookOutput

PropertyTypeDescription
suppressOutput?boolSuppress final output
cleanupActions?arrayCleanup details
sessionSummary?stringSession summary

ErrorOccurredHookInput

PropertyTypeDescription
errorstringError message
errorContext?stringOne of model_call, tool_execution, system, or user_input
recoverableboolWhether it is recoverable

ErrorOccurredHookOutput

PropertyTypeDescription
suppressOutput?boolSuppress error output
errorHandling?stringretry / skip / abort
retryCount?intRetry count
userNotification?stringMessage shown to user

ToolResultObject

Standard object for tool execution results.
PropertyTypeDescription
textResultForLlm?stringText result passed to the LLM
resultType?stringsuccess / failure / rejected / denied
resultForAssistant?arrayAssistant-facing result data

Best practices

  1. Avoid heavy sync work inside hooks. Offload when needed.
  2. Return null when no customization is required.
  3. Make permissionDecision explicit whenever possible.
  4. Do not over-suppress critical errors. Keep logs and notifications.
  5. Manage session state by session ID and clean up in onSessionEnd.
For the latest updates, see the GitHub repository.
Last modified on April 22, 2026