# How the i-have-adhd Plugin Handles the Always-On Flag in OpenCode

> Learn how the i-have-adhd plugin manages the always-on flag in OpenCode. Discover its use of a filesystem flag to inject ADHD-friendly rules via the experimental chat system transform hook.

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

---

**The i-have-adhd plugin uses a filesystem flag file at `~/.config/opencode/.i-have-adhd-always` to persistently inject ADHD-friendly rules into every model response via the `experimental.chat.system.transform` hook.**

The `ayghri/i-have-adhd` repository provides an OpenCode plugin that mirrors the behavior of the original Claude Code integration, allowing users to keep ADHD-friendly formatting rules active across all chat turns. When the **always-on flag** is enabled, the plugin automatically prepends specific behavioral instructions to the system prompt on every interaction. This implementation relies on a simple file-based toggle mechanism that checks for the presence of a hidden flag file before injecting the ruleset.

## Flag File Location and Detection

The plugin determines whether always-on mode is active by checking for the existence of a specific file in the user's OpenCode configuration directory. According to the source code in `.opencode/plugins/i-have-adhd.mjs`, the flag path is constructed using the `XDG_CONFIG_HOME` environment variable with a fallback to the standard `~/.config` directory:

```typescript
const flagPath = path.join(
  process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'),
  'opencode',
  '.i-have-adhd-always'
);

```

*Source: [.opencode/plugins/i-have-adhd.mjs, lines 30-33](https://github.com/ayghri/i-have-adhd/blob/main/.opencode/plugins/i-have-adhd.mjs#L30-L33)*

At the start of each chat turn, the **transform hook** checks this path using `fs.existsSync`. If the file is missing, the hook returns immediately without modifying the system prompt:

```typescript
let on = false;
try { on = fs.existsSync(flagPath); } catch (e) {}
if (!on) return;

```

*Source: [.opencode/plugins/i-have-adhd.mjs, lines 60-63](https://github.com/ayghri/i-have-adhd/blob/main/.opencode/plugins/i-have-adhd.mjs#L60-L63)*

## Transform Hook and Ruleset Injection

When the flag file exists, the plugin activates the `experimental.chat.system.transform` hook to modify the system prompt before it reaches the model. The implementation follows three distinct phases: reading the ruleset, constructing a notification header, and appending the content to the system messages.

### Reading the Skill Ruleset

The plugin references the `rulesetBody()` function to load the ADHD-friendly instructions from [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md). This function strips the YAML front-matter and trims trailing newlines, producing a clean text block identical to the one used by the traditional Claude Code hook.

*Source: [.opencode/plugins/i-have-adhd.mjs, lines 38-43](https://github.com/ayghri/i-have-adhd/blob/main/.opencode/plugins/i-have-adhd.mjs#L38-L43)*

### Injecting the Header and Rules

The plugin constructs a mandatory header that informs the model the ADHD mode is active and provides instructions for deactivation. It then appends this header and the ruleset body to the last system message, or creates a new system message if none exist:

```typescript
const header = 'ADHD MODE ACTIVE (always-on). The ruleset below applies to every response. '
              + '"stop adhd mode" or "normal mode" turns it off for this session; '
              + 'delete ' + flagPath + ' to turn always-on off for good.';
const injected = header + '\n\n' + body;
// Append to system prompt
if (output.system.length > 0) {
  output.system[output.system.length - 1] += '\n\n' + injected;
} else {
  output.system.push(injected);
}

```

*Source: [.opencode/plugins/i-have-adhd.mjs, lines 67-78](https://github.com/ayghri/i-have-adhd/blob/main/.opencode/plugins/i-have-adhd.mjs#L67-L78)*

## Enabling and Disabling Always-On Mode

Users control the always-on behavior through filesystem operations and natural language commands. The plugin recognizes three distinct control methods:

1. **Enable always-on**: Create the flag file to activate persistent injection across all sessions.
2. **Disable for current session**: Tell the model "stop adhd mode" or "normal mode" to remove the injection temporarily (per the skill's persistence rules).
3. **Permanently disable**: Delete the flag file to stop all future automatic injections.

Enable always-on using the command line:

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

```

Permanently disable by removing the file:

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

```

The same flag logic appears in the Claude Code reference implementation at `hooks/always-on.mjs`, which writes identical headers and rulesets to stdout when the flag exists.

*Source: [hooks/always-on.mjs, lines 15-23 and 36-40](https://github.com/ayghri/i-have-adhd/blob/main/hooks/always-on.mjs)*

## Summary

- The **always-on flag** is a file-based toggle located at `~/.config/opencode/.i-have-adhd-always` (or `$XDG_CONFIG_HOME/opencode/.i-have-adhd-always`).
- The plugin checks for this file at the start of every chat turn using `fs.existsSync` in the transform hook.
- When active, the plugin injects a header and the contents of [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) into the system prompt via the `experimental.chat.system.transform` hook.
- Users can disable the mode permanently by deleting the flag file, or temporarily by telling the model to stop ADHD mode.
- The implementation mirrors the behavior found in the Claude Code `hooks/always-on.mjs` reference implementation.

## Frequently Asked Questions

### Where is the always-on flag file stored?

The flag file is stored in the OpenCode configuration directory at `~/.config/opencode/.i-have-adhd-always` by default. If the `XDG_CONFIG_HOME` environment variable is set, the plugin uses that path instead, appending `/opencode/.i-have-adhd-always` to the custom configuration root.

### How do I temporarily disable ADHD mode without deleting the flag?

You can temporarily disable ADHD mode for the current session by telling the model "stop adhd mode" or "normal mode". According to the skill's persistence rules in [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md), this command removes the injected text for that specific conversation without deleting the flag file, allowing you to preserve the always-on setting for future chats.

### What hook does the plugin use to modify system prompts?

The plugin registers the `experimental.chat.system.transform` hook in `.opencode/plugins/i-have-adhd.mjs`. This hook intercepts the system prompt array before it is sent to the model, allowing the plugin to conditionally append the ADHD ruleset when the flag file is detected.

### Does this work with Claude Code as well?

Yes, the repository includes a separate implementation for Claude Code in `hooks/always-on.mjs` that uses identical flag-detection logic. Both implementations check for the same flag file location and inject the same ruleset content, ensuring consistent behavior across OpenCode and Claude Code environments.