# How Does the Always-On Hook Function in the i-have-adhd Project?

> Discover how the always-on hook in the i-have-adhd repository injects ADHD-friendly rules into Claude sessions. Learn about the SessionStart hook and user opt-in.

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

---

**TLDR: The always-on hook is a `SessionStart` hook in the `i-have-adhd` repository that automatically injects the full ADHD-friendly ruleset into every Claude session — but only when a user has explicitly opted in by creating a hidden flag file.**

The `ayghri/i-have-adhd` repository provides a set of skills and hooks that tune Claude Code's behavior for neurodivergent users. The always-on hook is the project's centerpiece for persistent ADHD guidance: instead of manually loading the ruleset per session, this hook reads and emits the rules automatically at session start, so the assistant is already primed to respond with ADHD-friendly structure before the first prompt. Understanding how this hook works is essential for anyone who wants to configure, extend, or debug it.

## How the Always-On Hook Works

The always-on hook is declared as a `SessionStart` hook and implemented as a **JavaScript module** (`always-on.mjs`) wrapped in a small wrapper that also detects platform-specific fallbacks. At runtime, it executes a fixed sequence of six steps, each designed to be quiet, safe, and non-blocking.

### 1. Determine the Opt-In Flag

The very first task of the hook is to check whether the user has explicitly enabled always-on mode. It does this by looking for a hidden file named **`.i-have-adhd-always`** inside the Claude configuration directory. The path is resolved as:

```text
$CLAUDE_CONFIG_DIR/.i-have-adhd-always

```

If the `$CLAUDE_CONFIG_DIR` environment variable is not set (which is common), the hook falls back to `~/.claude` as the default configuration path.

**Important:** Without this flag file, the hook does *nothing*. The user must specifically opt in for the persistent behavior.

### 2. Exit Silently When Not Opted In

If the flag file does not exist, the script **immediately exits with status code `0`**. This ensures the hook never blocks, delays, or prompts at `SessionStart` for users who have not enabled this feature. Because it exits cleanly, the hook introduces zero overhead for the majority of users.

### 3. Locate the Skill File

Only after confirming the opt-in flag does the hook resolve the path to the actual ruleset: [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md). Instead of relying on environment variables, it computes this path **relative to the hook's own location**:

```mjs
const skillPath = path.join(path.dirname(new URL(import.meta.url).pathname), 'skills/i-have-adhd/SKILL.md');

```

This relative resolution means the hook remains portable — you can move the entire repo, or symlink it, and the hook will still find the ruleset as long as the directory structure is intact.

### 4. Read and Clean the Skill Content

Next, the hook reads [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) as UTF-8 text. The file contains a YAML front-matter block (a series of `---` delimited lines that hold metadata). The hook strips this block with a regular expression:

```js
const withoutFrontMatter = raw.replace(/^---\s*\n[\s\S]*?\n---\s*\n/, '');

```

It also trims the trailing blank lines so that the injected output is compact and clean.

### 5. Emit the ADHD Mode Banner

Now the fun part. The hook writes the cleaned ruleset to **stdout**, prefixed with a short banner that:

- Notes that **ADHD mode is active**.
- Explains how to disable it for the *current* session by typing `"stop adhd mode"` in the chat.
- Explains how to permanently turn it off by deleting the `.i-have-adhd-always` flag file.

Because Stdout is captured by Claude Code at `SessionStart`, this text becomes part of the conversation — the model sees the banner plus the full ruleset and adjusts its behavior accordingly. The banner is deliberately small so as not to consume a lot of tokens.

### 6. Robust Error Handling

The entire logic runs inside a try/catch block. Any unexpected error (e.g., file read permission denials, path issues) is caught and the script **still** exits with status code `0`. This guarantee means the hook can never cause a session to fail to start, even if the repository becomes malformed or the disk has transient issues.

## Cross-Platform Runtime Support

The primary implementation is JavaScript (`always-on.mjs`), which runs on the **Node.js runtime** and therefore works on macOS, Linux, and Windows.

The repository also ships **Bash** and **PowerShell** fallback wrappers in the [`hooks.json`](https://github.com/ayghri/i-have-adhd/blob/main/hooks.json) declaration, making sure the hook functions even in environments that cannot execute the JS version (for example, where Node is not installed at the path the runtime expects). The actual configuration step is the same regardless of the shell:

**Enable always-on mode:**

```bash

# Unix-like shells

mkdir -p ~/.claude
touch ~/.claude/.i-have-adhd-always

```

```powershell

# PowerShell

$claudeDir = "$env:USERPROFILE\.claude"
New-Item -ItemType Directory -Force -Path $claudeDir
New-Item -ItemType File -Force -Path "$claudeDir\.i-have-adhd-always"

```

After creating the flag file, every new Claude session will start with the ADHD rules automatically injected.

**Disable always-on for the current session:**

Within a Claude chat, type **`stop adhd mode`** — the hook's banner tells the model to stop applying the rules for that session.

**Permanently disable always-on:**

```bash
rm ~/.claude/.i-have-adhd-always   # Unix-like shells

Remove-Item "$env:USERPROFILE\.claude\.i-have-adhd-always"  # PowerShell

```

## Key Files in the Repository

- **`always-on.mjs`** — the JavaScript implementation of the `SessionStart` hook.
- **[`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md)** — the markdown file containing the ADHD-friendly response rules that the hook injects.
- **[`hooks.json`](https://github.com/ayghri/i-have-adhd/blob/main/hooks.json)** — declares the hook type (`SessionStart`) and the entry point for the runtime.
- **[`test_always_on_hooks.py`](https://github.com/ayghri/i-have-adhd/blob/main/test_always_on_hooks.py)** — the unit test that verifies the hook's behavior under various conditions (flag present, flag absent, missing skill file, etc.).

## Summary

- The always-on hook is a **SessionStart hook** that only activates when the user has explicitly opted in with a `.i-have-adhd-always` flag file.
- It resolves the [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) file relative to its own location, strips the YAML frontmatter, and writes the ruleset to stdout with a banner.
- The hook exits `0` in *all* cases, including when disabled and when it throws an unexpected error — guaranteeing it never blocks a session.
- It requires no session start, is cross-platform (Node.js with Bash/PowerShell fallbacks), and both temporary (`"stop adhd mode"`) and permanent (deleting the flag) disable paths are built in.

## Frequently Asked Questions

### What token overhead does the always-on hook add per session?

Very little. It emits the banner plus the full [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) ruleset, which is typically a few hundred tokens. That cost is paid once per session, and the user can stop mode with a session with a meeting free temporary upgrade by typing `"stop adhd mode"` if they want to reduce it for a particular chat.

### How do I know the always-on hook is actually running?

Look for the banner in your first Claude response of a new session—it says "ADHD mode is active" and explains your disable options. Alternatively, check that the flag file exists: `~/.claude/.i-have-adhd-always`.

### What happens if I delete the [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) file while the hook is active?

The hook catches the resulting file-read error and still exits with code 0. The session will start normally, but no ADHD rules will be injected into that session, and no error will be shown (the hook is designed to be silent about failures).

### Does the hook work with Windows without any extra setup?

Yes, as long as Node.js is available on the machine — the flag creation is PowerShell-friendly, and the [`hooks.json`](https://github.com/ayghri/i-have-adhd/blob/main/hooks.json) also declares a PowerShell fallback. If Node.js is absent, the embedded fallback keeps the hook functional, though the instructions for the (Bash) unix syntax will still be the same.