How the Always-On Mechanism Works in i-have-adhd: A Technical Deep Dive
The always-on mechanism injects the full i-have-adhd ruleset into every Claude/Codex session by checking for a .i-have-adhd-always flag file at startup, then stripping YAML front-matter from SKILL.md and writing the processed rules to stdout via a SessionStart hook.
The always-on mechanism in ayghri/i-have-adhd provides persistent ADHD-friendly formatting across all AI coding sessions without requiring manual activation commands. This feature operates through a lightweight SessionStart hook architecture that detects user opt-in status via filesystem flags and dynamically injects behavioral rules before the model generates responses. Understanding this implementation reveals how cross-platform shell scripts and Node.js modules collaborate to ensure seamless session customization.
Opt-In Flag Detection System
The always-on mechanism uses a simple filesystem-based toggle to respect user consent. The hook checks for a hidden flag file named .i-have-adhd-always inside the Claude configuration directory, defaulting to ~/.claude unless overridden by the CLAUDE_CONFIG_DIR environment variable.
In hooks/always-on.mjs, the flag path is constructed using Node.js path utilities:
const claudeDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
const flagPath = path.join(claudeDir, ".i-have-adhd-always");
(see always‑on.mjs line 16‑18)
If the flag file does not exist, the hook exits silently without modifying the session:
if (!fs.existsSync(flagPath)) process.exit(0);
(see always‑on.mjs line 20)
This early return ensures zero overhead for users who have not opted into the always-on mechanism.
SessionStart Hook Architecture
The i-have-adhd repository implements the always-on mechanism as a SessionStart hook registered in hooks/hooks.json. This declarative configuration tells Claude Code (and compatible runtimes) to execute specific scripts before generating the first response in any session.
The architecture provides three platform-specific implementations:
- Node.js (
hooks/always-on.mjs) – Primary implementation for modern environments - POSIX Shell (
hooks/always-on.sh) – Fallback for Unix-like systems without Node - PowerShell (
hooks/always-on.ps1) – Native support for Windows environments
All three scripts perform identical logic: check the flag, locate SKILL.md, strip front-matter, and inject the ruleset with a banner message.
Node.js Hook Implementation
The primary always-on mechanism resides in hooks/always-on.mjs, which handles path resolution, file processing, and stdout injection.
Locating the Ruleset
When the flag is present, the script resolves the canonical skill definition relative to its own location, avoiding untrusted environment variables:
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
const skillPath = path.join(scriptDir, "..", "skills", "i-have-adhd", "SKILL.md");
(see always‑on.mjs line 23‑25)
Processing SKILL.md
The hook reads the skill file and performs two critical text transformations:
- Strip YAML front-matter – Removes metadata blocks delimited by
--- - Trim trailing newlines – Ensures clean output formatting
const body = fs.readFileSync(skillPath, "utf8")
.replace(/^---[^\S\r\n]*\r?\n[\s\S]*?\r?\n---[^\S\r\n]*(?:\r?\n|$)/, "")
.replace(/(?:\r?\n)+$/, "");
(see always‑on.mjs line 27‑34)
The regex pattern ^---[^\S\r\n]*\r?\n[\s\S]*?\r?\n---[^\S\r\n]*(?:\r?\n|$) specifically targets YAML front-matter while preserving the actual content rules.
Injecting the Ruleset
Finally, the processed rules are written to stdout with an explanatory banner that informs users how to disable the mode:
process.stdout.write(
"ADHD MODE ACTIVE (always‑on). The ruleset below applies to every response. " +
'"stop adhd mode" turns it off for this session; ' +
`delete ${flagPath} to turn always‑on off for good.\n\n${body}\n`
);
(see always‑on.mjs line 36‑40)
Cross-Platform Fallback Scripts
To ensure the always-on mechanism works across diverse development environments, the repository includes shell script fallbacks that mirror the Node.js logic.
POSIX Implementation
The always-on.sh script performs the same flag check using standard shell utilities:
claude_dir="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
flag_path="$claude_dir/.i-have-adhd-always"
[ -f "$flag_path" ] || exit 0
(see always‑on.sh line 9‑14)
The script uses printf and awk to strip front-matter and output the ruleset, ensuring compatibility with minimal dependencies.
PowerShell Implementation
Windows environments execute always-on.ps1, which implements identical path resolution and string manipulation using PowerShell cmdlets, maintaining feature parity across operating systems.
Safety and Error Handling
A critical design requirement of the always-on mechanism is that it never blocks session initialization. All implementations include defensive programming:
- Node.js: Logic wrapped in
try/catchblocks with silent failure - Shell scripts: Explicit
exit 0commands ensure the process terminates successfully even if file operations fail - Graceful degradation: If
SKILL.mdis missing or corrupted, the hook exits without crashing the Claude/Codex session
This fail-safe approach ensures that filesystem permissions issues or missing dependencies cannot prevent users from accessing their AI assistant.
Enabling and Disabling Always-On Mode
Users control the always-on mechanism through simple filesystem commands:
# Enable always-on permanently
touch ~/.claude/.i-have-adhd-always
# Check status
ls ~/.claude/.i-have-adhd-always
# Disable for current session only (type in chat)
"stop adhd mode"
# Disable permanently
rm ~/.claude/.i-have-adhd-always
The CLAUDE_CONFIG_DIR environment variable allows customization of the configuration directory location for non-standard installations.
Summary
- The always-on mechanism uses a filesystem flag (
.i-have-adhd-always) in the Claude config directory to determine whether to activate - SessionStart hooks in
hooks/hooks.jsontrigger the injection logic before every session begins - The Node.js implementation in
hooks/always-on.mjsstrips YAML front-matter fromskills/i-have-adhd/SKILL.mdand outputs the ruleset to stdout - Cross-platform fallbacks (
always-on.shandalways-on.ps1) ensure consistent behavior across Unix and Windows systems - Fail-safe design guarantees that hook failures never prevent session initialization, using
try/catchand explicitexit 0commands
Frequently Asked Questions
How do I enable the always-on mechanism in i-have-adhd?
Create an empty flag file at ~/.claude/.i-have-adhd-always (or $CLAUDE_CONFIG_DIR/.i-have-adhd-always). The SessionStart hook detects this file at the beginning of every Claude/Codex session and automatically injects the ADHD-friendly ruleset from skills/i-have-adhd/SKILL.md.
Why does the always-on mechanism strip YAML front-matter from SKILL.md?
The hook removes YAML front-matter (content between --- delimiters) because the injected ruleset must contain only the behavioral instructions for the AI model, not metadata. The regex pattern in always-on.mjs lines 27-34 specifically targets these delimiters to ensure clean injection into the session context.
Can I temporarily disable always-on mode without deleting the flag file?
Yes. During any active session, typing "stop adhd mode" instructs the model to ignore the always-on ruleset for that specific conversation. However, the next new session will re-inject the rules unless you permanently disable the feature by deleting the .i-have-adhd-always flag file.
What happens if the always-on hook encounters an error?
The hook is designed to fail silently. Both the Node.js implementation and shell script fallbacks use defensive error handling—try/catch blocks in JavaScript and explicit exit 0 commands in shell scripts—to ensure that filesystem errors or missing dependencies never block your ability to start a Claude/Codex session.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →