How to Run Python Unit Tests for i-have-adhd Hooks: A Complete Guide

Use python3 -m unittest discover -s tests -v to run the full test suite, or python3 -m unittest tests.test_always_on_hooks for hook-specific validation.

The i-have-adhd repository provides SessionStart hooks for Claude and Codex that automatically inject an ADHD ruleset into every session when users opt in. To ensure these cross-platform hooks work reliably, the project maintains a Python unit test suite in tests/test_always_on_hooks.py. This guide covers how to run Python unit tests for i-have-adhd hooks locally, what the tests verify, and how to interpret the results.

Prerequisites: Install Required Runtimes

The hook tests exercise three runtime environments: Node.js, Bash, and PowerShell. Install these before running tests.

On Linux/macOS:


# Node.js (required for the primary hook)

sudo apt-get install nodejs   # Debian/Ubuntu

brew install node             # macOS

# PowerShell (optional but tested)

sudo apt-get install powershell

On Windows:


# Using Chocolatey

choco install nodejs

# PowerShell is built-in; Bash available via WSL or Git Bash

Verify installations:

node --version
bash --version
pwsh --version

Clone and Navigate to the Repository

git clone https://github.com/ayghri/i-have-adhd.git
cd i-have-adhd

The test suite expects this directory structure:


i-have-adhd/
├── hooks/
│   ├── always-on.mjs
│   ├── always-on.sh
│   ├── always-on.ps1
│   └── hooks.json
├── skills/i-have-adhd/SKILL.md
└── tests/
    └── test_always_on_hooks.py

Run All Python Unit Tests

Execute the complete test discovery to validate the entire codebase:

python3 -m unittest discover -s tests -v

The -v (verbose) flag shows individual test names and results. Expect output like:


test_flag_absent_hooks_silent (tests.test_always_on_hooks.TestAlwaysOnHooks) ... ok
test_flag_present_shows_ruleset (tests.test_always_on_hooks.TestAlwaysOnHooks) ... ok
test_frontmatter_stripping (tests.test_always_on_hooks.TestAlwaysOnHooks) ... ok
...
----------------------------------------------------------------------
Ran 5 tests in 2.34s

OK

Run Only the Hook Tests

For rapid iteration during hook development, target the specific test module:

python3 -m unittest tests.test_always_on_hooks

Or with verbosity:

python3 -m unittest tests.test_always_on_hooks -v

What the Python Unit Tests Validate

The test_always_on_hooks.py suite performs comprehensive validation of the i-have-adhd hook system:

Temporary Environment Setup

  • Creates a mock plugin directory structure
  • Copies hooks/ and skills/ folders to isolated temp locations
  • Configures $CLAUDE_CONFIG_DIR pointing to a temporary path

Flag File Behavior

  • Absent flag: Verifies all three hook runtimes (node always-on.mjs, sh always-on.sh, pwsh always-on.ps1) produce no output
  • Present flag: Creates .i-have-adhd-always in the temp config directory and confirms the ADHD ruleset prints to stdout

Front-Matter Processing

The tests verify skills/i-have-adhd/SKILL.md parsing handles edge cases:

  • Standard YAML front-matter delimiters (---) are stripped correctly
  • Stray whitespace around delimiters doesn't break parsing
  • Unclosed delimiters are handled gracefully

Codex Launcher Configuration

Cross-references hooks/hooks.json against the actual hooks/always-on.mjs implementation:

  • Confirms the command field invokes the shared Node launcher
  • Validates environment variable references like $CLAUDE_CONFIG_DIR

Manual Hook Testing Outside Python

To observe hook behavior directly without the test framework:


# Without opt-in flag: silent

node hooks/always-on.mjs

# Enable opt-in

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

# Now produces output

node hooks/always-on.mjs

Test Bash and PowerShell variants:

sh hooks/always-on.sh          # Unix fallback

pwsh hooks/always-on.ps1       # Windows fallback

Remove the flag to silence output again:

rm ~/.claude/.i-have-adhd-always

Key Files in the Test System

File Purpose
tests/test_always_on_hooks.py Main Python unittest suite with TestAlwaysOnHooks class
hooks/always-on.mjs Primary Node.js hook implementation
hooks/always-on.sh Bash implementation for Unix compatibility
hooks/always-on.ps1 PowerShell implementation for Windows
hooks/hooks.json Claude/Codex hook configuration schema
skills/i-have-adhd/SKILL.md Source content injected by hooks

Troubleshooting Common Test Failures

Missing Runtime Errors

If you see FileNotFoundError or subprocess failures, verify the runtime is in your PATH:

which node
which pwsh

Permission Denied on Hooks

Ensure hook scripts are executable:

chmod +x hooks/always-on.sh
chmod +x hooks/always-on.mjs   # if directly executed

Windows-Specific Issues

PowerShell execution policy may block scripts. Adjust as needed:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Summary

Running Python unit tests for i-have-adhd hooks ensures cross-platform reliability of the SessionStart injection system:

  • Full suite: python3 -m unittest discover -s tests -v
  • Hook-only: python3 -m unittest tests.test_always_on_hooks
  • The tests in tests/test_always_on_hooks.py validate Node, Bash, and PowerShell runtimes
  • Flag file behavior, front-matter stripping, and launcher configuration are all verified
  • Manual testing requires the .i-have-adhd-always opt-in flag in ~/.claude/

Frequently Asked Questions

What Python version is required to run the i-have-adhd hook tests?

The tests use standard unittest from the Python standard library, compatible with Python 3.7+. No external test dependencies are required.

Why do the tests need Node.js and PowerShell installed?

The test suite invokes actual hook scripts via subprocess.run to verify real-world behavior. Since hooks/always-on.mjs, hooks/always-on.sh, and hooks/always-on.ps1 target different platforms, the tests exercise each runtime to catch environment-specific regressions.

Can I run the tests without PowerShell?

Yes, but tests targeting the PowerShell hook will be skipped or fail. The Node.js hook is the primary implementation; Bash and PowerShell serve as fallbacks. For full coverage on Linux/macOS, install PowerShell via your package manager.

What does "front-matter stripping" mean in the test context?

The skills/i-have-adhd/SKILL.md file contains YAML front-matter (metadata between --- delimiters) that Claude uses for skill discovery. The hooks must output only the ruleset content, not this metadata. The tests verify this stripping works correctly even with malformed delimiters.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →