How i-have-adhd Ensures Cross-Platform Parity for Its Hooks

i-have-adhd ensures cross-platform parity by maintaining a single source of truth in hooks/hooks.json while duplicating hook logic across Unix shell, PowerShell, and JavaScript runtimes that all reference the same flag file and ruleset.

The i-have-adhd repository implements an "always-on" hook system that must behave identically across fundamentally different execution environments. Rather than trying to abstract away platform differences with a complex compatibility layer, the project takes a deliberately simple approach: shared configuration, duplicated implementations, and a unified file-based toggle mechanism.

Central Configuration: The Single Source of Truth

At the heart of cross-platform parity sits hooks/hooks.json. This JSON file defines the hook name (always-on) and the environment variable path that controls activation. Every runtime—whether Bash, PowerShell, or Node.js—parses this same file to determine where to look for the toggle flag and what behavior to enable.

This design guarantees that any change to the hook's semantics propagates automatically. Update the flag path in one place, and all platforms follow. The configuration file eliminates the class of bugs where "it works on my shell but not in PowerShell."

Platform-Specific Implementations with Identical Logic

The project maintains three parallel implementations that mirror each other's behavior exactly:

Unix Shell (hooks/always-on.sh)

The Bash implementation checks for the presence of ~/.config/opencode/.i-have-adhd-always. If found, it injects the ADHD ruleset into the session context.

PowerShell (hooks/always-on.ps1)

The PowerShell cmdlet performs the identical check using Test-Path, targeting the same flag file path. The ruleset payload matches byte-for-byte with the Unix version.

JavaScript (hooks/always-on.mjs)

The Node-compatible version reads hooks/hooks.json, resolves the flag path, and conditionally returns the ruleset:

import { readFileSync, existsSync, unlinkSync } from 'fs';
import { resolve } from 'path';
import config from '../hooks/hooks.json';

const flagPath = resolve(process.env.HOME, '.config', 'opencode', '.i-have-adhd-always');

export function injectAlwaysOn() {
  if (!existsSync(flagPath)) return '';               // hook disabled
  const rules = readFileSync('rules.txt', 'utf8');     // ADHD ruleset
  return `ADHD MODE ACTIVE (always‑on).\n${rules}\n\n` +
         `Delete ${flagPath} to turn always‑on off for good.\n`;
}

All three scripts contain the same textual payload (the ADHD ruleset) and follow the same file-based toggle mechanism. This duplication is intentional—it trades minor maintenance overhead for absolute behavioral consistency.

Runtime Integration Through Unified APIs

The OpenCode plugin at .opencode/plugins/i-have-adhd.mjs imports directly from the JavaScript hook:

import { injectAlwaysOn } from '../../hooks/always-on.mjs';

export function onSessionStart() {
  const hookPayload = injectAlwaysOn();
  if (hookPayload) {
    // inject the payload into the session context for every model
    this.context.addHook('always-on', hookPayload);
  }
}

When a session starts, the plugin calls injectAlwaysOn()—the same function that shell scripts expose through their own wrappers. This ensures that OpenCode, Pi, OMP, and Claude runtimes honor the "always-on" flag uniformly, regardless of how the underlying host environment implements file system access.

Consistent Toggle Semantics Across Platforms

Users control the hook through a single, portable mechanism:


# Enable "always-on" (works on any platform)

touch ~/.config/opencode/.i-have-adhd-always

# Disable "always-on"

rm ~/.config/opencode/.i-have-adhd-always

Because every implementation references the exact same path defined in hooks/hooks.json, the state cannot diverge between platforms. A flag created in PowerShell is immediately visible to the Bash script and the JavaScript runtime. No registry keys, no environment variable synchronization, no platform-specific state management.

Automated Testing for Parity Guarantees

The test suite in tests/test_always_on_hooks.py exercises each implementation against a shared specification:

  • Same rule set injection — Verifies that Bash, PowerShell, and JavaScript return identical payload content when the flag is present
  • Correct toggle behavior — Confirms that absence of the flag file disables the hook on all platforms
  • Path resolution — Ensures that relative path handling produces equivalent results across runtimes

This automated verification catches regressions where a platform-specific script might drift from canonical behavior. A failing test on any implementation blocks the entire change, enforcing cross-platform parity at CI time.

Summary

  • hooks/hooks.json provides the single source of truth for hook configuration
  • Three parallel implementations (.sh, .ps1, .mjs) share identical logic and payload
  • Unified flag file at ~/.config/opencode/.i-have-adhd-always guarantees consistent state
  • injectAlwaysOn() function exposes the same API to shell scripts and Node-based runtimes
  • tests/test_always_on_hooks.py enforces behavioral parity through automated verification

Frequently Asked Questions

What happens if the flag file exists on one machine but not another?

The hook is per-machine stateful. The flag file lives in the user's home directory (~/.config/opencode/), so it does not synchronize across devices by default. Each machine maintains its own "always-on" preference. To enable globally, users must create the flag on each target system—or sync their dotfiles.

Why duplicate the implementation instead of using a cross-platform abstraction?

The i-have-adhd project prioritizes behavioral correctness over code reuse. Shell, PowerShell, and JavaScript have fundamentally different execution models, file system APIs, and error handling. Duplicating the (small, simple) logic eliminates an entire category of abstraction bugs where "it should work the same" turns out to be false. The test suite ensures the duplicates stay synchronized.

Can I use the "always-on" hook outside of OpenCode?

Yes. The shell scripts function standalone—source hooks/always-on.sh in your .bashrc or import hooks/always-on.ps1 in your PowerShell profile. The JavaScript module works in any Node environment. The OpenCode plugin is simply one consumer of the shared hook API.

How does the project handle path differences between Windows and Unix?

The JavaScript implementation uses Node's path.resolve() and process.env.HOME (which maps correctly on Windows via USERPROFILE). The shell and PowerShell scripts both hardcode the Unix-style path ~/.config/opencode/, which PowerShell resolves correctly through its tilde expansion. The JSON configuration centralizes this path definition for future flexibility.

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 →