# PreToolUse vs PostToolUse Hooks in context-mode: Complete Session Tracking Guide

> Understand PreToolUse vs PostToolUse hooks in context-mode for complete session tracking. Learn how hooks enforce policies and track events in mksglu/context-mode.

- Repository: [Mert Köseoğlu/context-mode](https://github.com/mksglu/context-mode)
- Tags: deep-dive
- Published: 2026-04-24

---

**PreToolUse hooks execute before tool invocation to enforce routing policies and modify requests, while PostToolUse hooks execute after completion to extract and persist session events to the SQLite database.**

The `context-mode` repository implements a dual-hook architecture for intercepting AI assistant tool calls. Understanding the distinction between **PreToolUse** and **PostToolUse** hooks is essential for developers building session-aware applications that need to control execution flow and maintain persistent conversation history.

## What Are PreToolUse Hooks?

PreToolUse hooks run immediately before an external tool executes. Located in platform-specific adapters like [`src/adapters/vscode-copilot/index.ts`](https://github.com/mksglu/context-mode/blob/main/src/adapters/vscode-copilot/index.ts), these hooks receive the raw tool request containing `tool_name` and `tool_input`.

According to the source code in [`src/pi-extension.ts`](https://github.com/mksglu/context-mode/blob/main/src/pi-extension.ts), the routing logic calls `routing.routePreToolUse()` to evaluate each request:

```typescript
// src/pi-extension.ts
if (hookEventName === "PreToolUse") {
  const decision = routing.routePreToolUse(
    toolName,
    toolInput,
    projectDir,
    "pi-extension"
  );
  // decision may contain `reject` or `additionalContext`
}

```

These hooks serve three primary purposes:

- **Enforce allow-list policies**: Block disallowed tools before execution
- **Mutate requests**: Inject additional context or rewrite arguments
- **Abort execution**: Return a `PreToolUseResponse` with `reject: true` to prevent the call

Crucially, PreToolUse hooks do not write session data. They are purely advisory and influence how a session will look later without persisting anything to the database.

## What Are PostToolUse Hooks?

PostToolUse hooks execute after a tool has finished and produced results. These hooks are the only mechanism for persisting session data in context-mode.

The [`src/session/extract.ts`](https://github.com/mksglu/context-mode/blob/main/src/session/extract.ts) file transforms the raw PostToolUse payload into structured `SessionEvent` objects:

```typescript
// src/session/extract.ts
export function extractPostToolUse(input: HookInput): SessionEvent[] {
  const events: SessionEvent[] = [];
  events.push(...extractFileAndRule(input));
  events.push(...extractCwd(input));
  events.push(...extractError(input));
  return events;
}

```

Immediately after extraction, [`src/session/db.ts`](https://github.com/mksglu/context-mode/blob/main/src/session/db.ts) writes these events to the per-project SQLite database:

```typescript
// src/session/db.ts
insertEvent(
  sessionId: string,
  event: SessionEvent,
  sourceHook: string = "PostToolUse"
): void {
  this.stmt(S.insertEvent).run(
    sessionId,
    event.type,
    event.category,
    event.priority,
    event.data,
    sourceHook,
    Date.now()
  );
}

```

PostToolUse hooks receive the tool output and any error information, enabling comprehensive session tracking of file reads, edits, directory changes, and failures.

## Key Differences Between PreToolUse and PostToolUse

| Aspect | PreToolUse | PostToolUse |
|--------|------------|-------------|
| **Execution timing** | Before tool invocation | After tool completion |
| **Input data** | Raw tool request (`tool_name`, `tool_input`) | Tool results (`tool_response`, errors) |
| **Session persistence** | No database writes | Writes to SQLite via `SessionDB.insertEvent()` |
| **Control capabilities** | Can reject or modify requests | Records immutable history |
| **Adapter flags** | `preToolUse: boolean` in [`src/adapters/types.ts`](https://github.com/mksglu/context-mode/blob/main/src/adapters/types.ts) | `postToolUse: boolean` in [`src/adapters/types.ts`](https://github.com/mksglu/context-mode/blob/main/src/adapters/types.ts) |

The [`src/adapters/types.ts`](https://github.com/mksglu/context-mode/blob/main/src/adapters/types.ts) file defines these capabilities explicitly:

```typescript
// src/adapters/types.ts
export interface AdapterCapabilities {
  /** Platform supports PreToolUse / BeforeTool hooks. */
  preToolUse: boolean;
  /** Platform supports PostToolUse / AfterTool hooks. */
  postToolUse: boolean;
}

```

## Architectural Flow: How the Hooks Work Together

The complete lifecycle of a tool call in context-mode follows this sequence:

1. **Request interception**: Adapter calls `parsePreToolUseInput` to build a `PreToolUseEvent`
2. **Policy enforcement**: `routing.routePreToolUse()` (used in [`src/opencode-plugin.ts`](https://github.com/mksglu/context-mode/blob/main/src/opencode-plugin.ts) and [`src/openclaw-plugin.ts`](https://github.com/mksglu/context-mode/blob/main/src/openclaw-plugin.ts)) evaluates permissions
3. **Conditional execution**: If allowed, the external tool runs with potentially modified inputs
4. **Result processing**: Adapter calls `parsePostToolUseInput` to create a `PostToolUseEvent`
5. **Event extraction**: `extractPostToolUse()` in [`src/session/extract.ts`](https://github.com/mksglu/context-mode/blob/main/src/session/extract.ts) generates `SessionEvent` objects
6. **Persistence**: `insertEvent()` stores data with `sourceHook: "PostToolUse"` in the SQLite database

This dual-hook design provides complete visibility: PreToolUse controls access and augmentation before execution, while PostToolUse records actual outcomes for session-aware resumptions.

## Summary

- **PreToolUse hooks** execute before tool calls in [`src/pi-extension.ts`](https://github.com/mksglu/context-mode/blob/main/src/pi-extension.ts) and related plugins to enforce routing policies, mutate inputs, or reject requests entirely without persisting data.
- **PostToolUse hooks** execute after completion, serving as the sole mechanism for session tracking by extracting events in [`src/session/extract.ts`](https://github.com/mksglu/context-mode/blob/main/src/session/extract.ts) and persisting them via [`src/session/db.ts`](https://github.com/mksglu/context-mode/blob/main/src/session/db.ts).
- Both hooks implement capability flags defined in [`src/adapters/types.ts`](https://github.com/mksglu/context-mode/blob/main/src/adapters/types.ts) and require platform-specific adapters to parse inputs and format responses.
- Only PostToolUse writes to the session database, making it the authoritative source for conversation history.

## Frequently Asked Questions

### Can PreToolUse hooks modify the tool input before execution?

Yes. PreToolUse hooks can mutate requests by returning a `PreToolUseResponse` containing `overrideInput` or `additionalContext`. This allows the system to inject project-wide context snippets or rewrite arguments before the tool receives them, as implemented in the routing logic across [`src/opencode-plugin.ts`](https://github.com/mksglu/context-mode/blob/main/src/opencode-plugin.ts) and [`src/openclaw-plugin.ts`](https://github.com/mksglu/context-mode/blob/main/src/openclaw-plugin.ts).

### Why don't PreToolUse hooks write session data?

PreToolUse hooks are advisory-only because they execute before the tool produces results. Since no outcome exists yet, there is nothing to record for session history. The database writes occur exclusively in PostToolUse through `SessionDB.insertEvent()` with the explicit `sourceHook` parameter set to "PostToolUse".

### Which adapters support these hooks?

All platform adapters in the `src/adapters/` directory support both hooks, including VS Code Copilot, OpenClaw, and Kiro implementations. Each adapter exposes `preToolUse` and `postToolUse` boolean flags in the `AdapterCapabilities` interface and provides `parsePreToolUseInput`, `formatPreToolUseResponse`, and their PostToolUse counterparts.

### How does context-mode handle tool rejections?

When `routing.routePreToolUse()` determines a tool should be blocked (such as a dangerous Bash command), it returns a `PreToolUseResponse` with `reject: true`. The adapter formats this response back to the client, preventing execution entirely without creating any session record in the database.