# How Session Event Hooks Activate the i-have-adhd Skill: Hook Matcher Logic Explained

> Learn how i-have-adhd skill activates using session event hooks and the hook matcher logic. Discover how Pi-runtime hooks, saved state, and CLI flags influence skill injection into your conversation context.

- Repository: [Ayoub Ghriss/i-have-adhd](https://github.com/ayghri/i-have-adhd)
- Tags: internals
- Published: 2026-08-29

---

**The i-have-adhd extension uses three Pi-runtime hooks—`session_start`, `session_tree`, and `session_compact`—to determine skill activation by checking saved state, CLI flags, and configuration before injecting ADHD-specific rules into the conversation context.**

The ayghri/i-have-adhd repository implements a sophisticated **hook matcher** system that monitors session lifecycle events to activate its accessibility features. This TypeScript extension determines precisely when to enable its ADHD-specific skill by evaluating configuration states and synchronizing rules across session boundaries.

## The Three Session Hooks That Drive Activation

The core **hook matcher logic** resides in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts), where the extension registers three critical Pi-runtime hooks that intercept session events. Each hook triggers specific state management functions to determine whether the skill should activate, restore previous state, or synchronize existing rules.

### session_start and session_tree Hooks

Both the `session_start` and `session_tree` hooks invoke the **`restoreState`** function (lines 161-171) to evaluate activation conditions. The `session_start` hook fires at the beginning of new sessions, while `session_tree` triggers when the session tree reconstructs after reloads (lines 136-174).

These hooks perform the initial **activation check** by calling `restoreState(ctx)`, which determines whether to inject the ADHD ruleset based on user configuration and persisted state.

### session_compact Hook

The `session_compact` hook triggers **`syncContext`** (lines 134-158) during session log compaction when old markers are removed (lines 136-180). Unlike the start hooks, this hook focuses on maintaining consistency rather than initial activation, ensuring the rule-injection state matches the current `enabled` flag throughout the conversation lifecycle.

## restoreState: Determining the Enabled State

The **`restoreState`** function implements the primary **activation logic** that decides whether the skill should inject its ruleset into the current session. This function evaluates four conditional sources in hierarchical order:

1. **Previously saved state** via `getSavedState`
2. **CLI flag** via `pi.getFlag("adhd")`  
3. **User configuration** via `config.alwaysOn`
4. **Filesystem marker** via `existsSync(alwaysOnFlag)` checking for `.i-have-adhd-always`

```typescript
// Inside restoreState – decides whether the skill is enabled
const enabledByDefault =
  pi.getFlag("adhd") === true ||
  config.alwaysOn === true ||
  existsSync(alwaysOnFlag);
enabled = savedState ?? enabledByDefault;

```

After determining the `enabled` boolean, the function updates the UI status via `updateStatus` and synchronizes the conversation context through `syncContext(ctx)`.

## syncContext: Rule Injection and Synchronization

The **`syncContext`** function manages the actual injection and removal of ADHD guidelines from the conversation. Located at lines 134-158 in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts), this function uses **`rulesAreInContext`** (lines 105-111) to check whether the latest rules marker (`RULES_MESSAGE_TYPE`) remains active and hasn't been superseded by a disabled marker (`DISABLED_MESSAGE_TYPE`).

```typescript
// Inside syncContext – injects or removes the rule set
if (enabled && !injected) {
  pi.sendMessage({ customType: RULES_MESSAGE_TYPE, content: rules }, { triggerTurn: false });
}
if (!enabled && injected) {
  pi.sendMessage({ customType: DISABLED_MESSAGE_TYPE, content: DISABLED_NOTICE }, { triggerTurn: false });
}

```

When `enabled` is true but rules are missing, the function injects the ruleset from [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md). If the mode is disabled but stale rules persist, it sends a `DISABLED_MESSAGE_TYPE` notice to remove them.

## Source Code Architecture

The activation logic spans three key files that work together to implement the **session event hook matcher**:

- **[`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts)**: Contains the hook registrations, `restoreState` activation logic, and `syncContext` synchronization (lines 105-180).
- **[`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md)**: Stores the actual ADHD-friendly ruleset injected when activation conditions are met.
- **[`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts)**: Provides the `latestMarkerIsActive` utility that `rulesAreInContext` uses to validate rule presence in the conversation context.

## Summary

- **Three hooks trigger activation**: `session_start` and `session_tree` handle initial activation via `restoreState`, while `session_compact` maintains state via `syncContext`.
- **Hierarchical configuration**: The skill activates based on saved state, CLI `--adhd` flags, `alwaysOn` config, or the presence of a `.i-have-adhd-always` file.
- **Rule synchronization**: The `syncContext` function ensures conversation context matches the enabled state by injecting `RULES_MESSAGE_TYPE` or removing it with `DISABLED_MESSAGE_TYPE`.
- **Marker-based validation**: The `rulesAreInContext` function checks active markers to prevent duplicate rule injection or orphaned rulesets.

## Frequently Asked Questions

### What session events trigger the i-have-adhd skill activation?

The skill responds to three session events: `session_start` (new sessions), `session_tree` (session reconstruction after reloads), and `session_compact` (log compaction). The first two trigger full state restoration, while the compaction event only synchronizes existing rules with the current enabled state.

### How does the hook matcher determine if the skill should be enabled?

The matcher evaluates four sources in `restoreState`: previously saved state from `getSavedState`, the CLI flag `pi.getFlag("adhd")`, the configuration value `config.alwaysOn`, and the filesystem marker `.i-have-adhd-always`. If any indicate activation (with saved state taking precedence), the skill injects its ruleset.

### What prevents duplicate rule injection during long conversations?

The `syncContext` function uses `rulesAreInContext` (lines 105-111) to check for existing `RULES_MESSAGE_TYPE` markers before injection. If rules are already present and active, the function skips sending new messages. During compaction, it validates whether existing rules match the current enabled state and corrects any discrepancies.

### Where does the extension store the actual ADHD guidelines?

The ruleset content resides in [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md), while the activation logic lives in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) (lines 136-180). The [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts) file provides the marker validation utilities that prevent state desynchronization during session events.