How the i‑have‑adhd Skill Manages Restating Context Across Multiple User Messages
The skill persists an enabled flag in the session tree and injects a hidden rules message (customType: i-have-adhd-rules) into the model context on every turn, allowing the LLM to automatically restate the current step by following the persistent instructions in skills/i-have-adhd/SKILL.md.
The ayghri/i-have-adhd repository implements a Pi/OMP runtime extension that solves the problem of restating context across multiple user messages for users with ADHD. Rather than manually tracking conversation state in code, the system leverages persistent session entries and non-display system prompts to ensure the model continuously summarizes progress (e.g., "step 3 of 5 done") throughout long interactions.
Persisting the ADHD Mode Flag
The extension maintains session continuity by storing the enabled state in a custom session entry. When a user toggles the skill via commands like /i-have-adhd, "on", "off", or stop phrases such as "stop adhd mode", the system records the mode using a custom session entry of type i-have-adhd-state (defined as STATE_ENTRY_TYPE in extensions/i-have-adhd.ts).
The getSavedState() function scans the session tree for the latest entry of this type, while restoreState() invokes this check whenever a session starts or restores. This guarantees that restating context across multiple user messages resumes correctly even after interruptions or browser reloads.
Loading and Injecting Hidden Rules
The actual restatement logic resides in skills/i-have-adhd/SKILL.md, which contains the human-readable rule "Restate state every turn". The loadRules() function in extensions/i-have-adhd.ts loads this file and strips its front-matter to extract the raw instructions.
When ADHD mode is enabled and the rules are not already present in the model’s context, syncContext() injects a custom message with the following properties:
pi.sendMessage(
{
customType: "i-have-adhd-rules",
content: `${RULES_HEADER}\n\n${rules}`,
display: false,
},
{ triggerTurn: false },
);
The display: false flag ensures the user never sees the raw ruleset, while customType: "i-have-adhd-rules" creates a marker that the runtime can detect later.
Detecting Active Rules with Context Markers
To avoid duplicate injections and to verify that restating context across multiple user messages remains active, the system uses context markers. The latestMarkerIsActive() function in extensions/context-compat.ts walks the list of context messages returned by the runtime:
function latestMarkerIsActive(
messages: readonly ContextMessageMarker[],
activeType: string,
disabledType: string,
) {
let active = false;
for (const message of messages) {
if (message.role !== "custom" && message.type !== "custom_message") continue;
if (message.customType === activeType) active = true;
else if (message.customType === disabledType) active = false;
}
return active;
}
This helper returns true only if the most recent marker corresponds to the rules message and no subsequent "disabled" marker exists. The rulesAreInContext() function wraps this logic, feeding it the array from contextMessages() to determine whether the rules are still visible to the model.
Automatic State Restatement via Persistent Rules
The skill itself does not programmatically generate "step X of Y" strings. Instead, it relies on the persistent presence of the rules in the model context. Because the i-have-adhd-rules message remains injected across turns, the LLM honors rule 5 ("Restate state every turn") and automatically includes a state summary in each response.
When the user issues a stop phrase like stop adhd mode or normal mode, the system calls setEnabled(false), which injects a disabling marker (customType: "i-have-adhd-disabled"). This marker appears after the rules message in the context array, causing latestMarkerIsActive() to return false and ending the restatement behavior.
Lifecycle Hooks and Session Events
The extension registers for three critical events in hooks/hooks.json to ensure restating context across multiple user messages remains consistent:
- session_start: Triggers
restoreState()to check thei-have-adhd-stateentry - session_tree: Re-evaluates the session tree structure to locate persistent state markers
- session_compact: Ensures the ruleset marker survives context window compression
These hooks, combined with the runtime registration in package.json, guarantee that the mode and rule presence are re-evaluated whenever the session is restarted, reconstructed, or compacted.
Summary
- Session persistence: The enabled flag is stored as a custom session entry (
i-have-adhd-state) and restored viagetSavedState()on startup. - Hidden rules injection:
syncContext()loads rules fromskills/i-have-adhd/SKILL.mdand injects them as a non-display message withcustomType: "i-have-adhd-rules". - Marker-based detection:
latestMarkerIsActive()inextensions/context-compat.tsverifies rule presence by scanning for the most recent context marker. - LLM-driven restatement: The model automatically restates state because the persistent rules remain visible in its context until a disabled marker is injected.
- Lifecycle management: Hooks for
session_start,session_tree, andsession_compactensure continuity across session interruptions.
Frequently Asked Questions
How does the skill know whether to restate the context?
The extension checks whether the most recent context marker is of type i-have-adhd-rules using latestMarkerIsActive() in extensions/context-compat.ts. If this function returns true, the rules are present in the model's context window, and the LLM will follow the instruction to restate state every turn.
What happens when the user disables ADHD mode?
When the user types "stop adhd mode" or "normal mode", the extension calls setEnabled(false), which injects a new marker with customType: "i-have-adhd-disabled" into the context. This marker appears after the rules message, causing latestMarkerIsActive() to return false and effectively removing the restatement instruction from the model's working context.
Where are the restatement rules defined?
The rules are defined in skills/i-have-adhd/SKILL.md, specifically rule 5 which states "Restate state every turn". The loadRules() function in extensions/i-have-adhd.ts reads this file at runtime, strips the front-matter, and caches the content for injection into the model context.
Does the skill manually parse the current step from the conversation?
No. The extension does not parse conversation history to extract step numbers. Instead, it relies on the LLM's ability to track state internally while following the persistent rule to restate progress on every turn. The skill only manages the presence or absence of the rules message in the context window; the actual state summary is generated by the model itself.
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 →