Примечание.
Второй пилот SDK is currently in Technical Preview. Functionality and availability are subject to change.
The onPreToolUse hook is called before a tool executes. Use it to:
- Approve or deny tool execution
- Modify tool arguments
- Add context for the tool
- Suppress tool output from the conversation
Hook signature
import type { PreToolUseHookInput, HookInvocation, PreToolUseHookOutput } from "@github/copilot-sdk";
type PreToolUseHandler = (
input: PreToolUseHookInput,
invocation: HookInvocation
) => Promise<PreToolUseHookOutput | null | undefined>;
For hook signatures in Python, Go, and .NET, see the github/copilot-sdk repository.
Input
| Field | Type | Description |
|---|---|---|
timestamp | number | Unix timestamp when the hook was triggered |
cwd | string | Current working directory |
toolName | string | Name of the tool being called |
toolArgs | object | Arguments passed to the tool |
Output
Return null or undefined to allow the tool to execute with no changes. Otherwise, return an object with any of the following fields.
| Field | Type | Description |
|---|---|---|
permissionDecision | "allow" | "deny" | "ask" | Whether to allow the tool call |
permissionDecisionReason | string | Explanation shown to user (for deny/ask) |
modifiedArgs | object | Modified arguments to pass to the tool |
additionalContext | string | Extra context injected into the conversation |
suppressOutput | boolean | If true, tool output won't appear in conversation |
Permission decisions
| Decision | Behavior |
|---|---|
"allow" | Tool executes normally |
"deny" | Tool is blocked, reason shown to user |
"ask" | User is prompted to approve (interactive mode) |
Examples
Allow all tools (logging only)
const session = await client.createSession({
hooks: {
onPreToolUse: async (input, invocation) => {
console.log(
`[${invocation.sessionId}] `
+ `Calling ${input.toolName}`
);
console.log(
` Args: ${JSON.stringify(input.toolArgs)}`
);
return { permissionDecision: "allow" };
},
},
});
For examples in Python, Go, and .NET, see the github/copilot-sdk repository.
Block specific tools
const BLOCKED_TOOLS = [
"shell", "bash", "write_file", "delete_file",
];
const session = await client.createSession({
hooks: {
onPreToolUse: async (input) => {
if (BLOCKED_TOOLS.includes(input.toolName)) {
return {
permissionDecision: "deny",
permissionDecisionReason:
`Tool '${input.toolName}' `
+ `is not permitted in this environment`,
};
}
return { permissionDecision: "allow" };
},
},
});
Modify tool arguments
const session = await client.createSession({
hooks: {
onPreToolUse: async (input) => {
// Add a default timeout to all shell commands
if (
input.toolName === "shell" && input.toolArgs
) {
const args = input.toolArgs as {
command: string;
timeout?: number;
};
return {
permissionDecision: "allow",
modifiedArgs: {
...args,
timeout: args.timeout ?? 30000,
},
};
}
return { permissionDecision: "allow" };
},
},
});
Restrict file access to specific directories
const ALLOWED_DIRECTORIES = [
"/home/user/projects", "/tmp",
];
const session = await client.createSession({
hooks: {
onPreToolUse: async (input) => {
if (
input.toolName === "read_file"
|| input.toolName === "write_file"
) {
const args = input.toolArgs as {
path: string;
};
const isAllowed =
ALLOWED_DIRECTORIES.some((dir) =>
args.path.startsWith(dir)
);
if (!isAllowed) {
return {
permissionDecision: "deny",
permissionDecisionReason:
`Access to '${args.path}' `
+ `is not permitted. `
+ `Allowed directories: `
+ ALLOWED_DIRECTORIES.join(", "),
};
}
}
return { permissionDecision: "allow" };
},
},
});
Suppress verbose tool output
const VERBOSE_TOOLS = ["list_directory", "search_files"];
const session = await client.createSession({
hooks: {
onPreToolUse: async (input) => {
return {
permissionDecision: "allow",
suppressOutput: VERBOSE_TOOLS.includes(input.toolName),
};
},
},
});
Add context based on tool
const session = await client.createSession({
hooks: {
onPreToolUse: async (input) => {
if (input.toolName === "query_database") {
return {
permissionDecision: "allow",
additionalContext:
"Remember: This database uses "
+ "PostgreSQL syntax. "
+ "Always use parameterized queries.",
};
}
return { permissionDecision: "allow" };
},
},
});
Best practices
- Always return a decision. Returning
nullallows the tool, but being explicit with{ permissionDecision: "allow" }is clearer. - Provide helpful denial reasons. When denying, explain why so users understand what happened.
- Be careful with argument modification. Ensure modified arguments maintain the expected schema for the tool.
- Consider performance. Pre-tool hooks run synchronously before each tool call. Keep them fast.
- Use
suppressOutputjudiciously. Suppressing output means the model won't see the result, which may affect conversation quality. - Be mindful of sensitive data. Tool arguments and results may contain secrets, file paths, or personally identifiable information. Avoid logging or exposing this data in production environments.