# How the i-have-adhd Extension Tracks Context with latestMarkerIsActive in Pi

> Learn how the i-have-adhd extension uses latestMarkerIsActive to track context and maintain ADHD friendly formatting in Pi conversations. Discover its active state verification.

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

---

**The i-have-adhd extension maintains ADHD-friendly formatting rules by scanning conversation history with the `latestMarkerIsActive` utility to verify whether the most recent context marker indicates an active or disabled state.**

The `i-have-adhd` extension for the Pi AI assistant ensures that specialized formatting guidelines remain synchronized with the model's context throughout extended conversations. According to the ayghri/i-have-adhd source code, the extension tracks whether its ruleset is currently injected by analyzing custom message markers in the session history using a dedicated compatibility layer. This tracking mechanism relies on the `latestMarkerIsActive` function defined in [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts) to determine the current state of ADHD accommodation rules.

## The latestMarkerIsActive Utility

The core logic for context tracking resides in the `latestMarkerIsActive` function within [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts) (lines 41-61). This utility determines whether a specific marker type represents the current active state by performing a chronological scan of conversation messages.

The function accepts three parameters: the array of context messages, the marker type representing the enabled state (`RULES_MESSAGE_TYPE`), and the marker type representing the disabled state (`DISABLED_MESSAGE_TYPE`). It iterates through messages sequentially, setting an internal flag to `true` when encountering the rules marker and flipping it to `false` when encountering the disabled marker. After processing the entire array, the final boolean value indicates whether the rules are currently active based on the most recent relevant marker in the history.

## Collecting Context Messages

Before scanning can occur, the extension must safely extract the conversation history from Pi's session manager. The `contextMessages` function in [`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts) (lines 12-39) provides this abstraction.

This utility attempts to read messages through multiple API surface areas, checking for either `buildSessionContext().messages` or `buildContextEntries()` methods on the session manager object. If these methods are unavailable or throw exceptions, the function gracefully returns an empty array rather than crashing. This defensive programming ensures the extension remains compatible across different Pi versions while providing a standardized `ContextMessageMarker` array for downstream processing.

## Scanning for the Newest Marker

Once the message array is retrieved, the extension determines the current rules state through a linear chronological scan. The implementation in `latestMarkerIsActive` (lines 48-58) processes each message individually.

When the scan encounters a message whose `customType` property matches `RULES_MESSAGE_TYPE`, it sets a local `active` variable to `true`. If it subsequently encounters a message with `customType` matching `DISABLED_MESSAGE_TYPE`, it updates the variable to `false`. This simple state machine approach ensures that only the most recent marker of either type influences the final result, effectively ignoring older markers that may have been superseded by newer state changes.

## Synchronizing Context State

The main extension file [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) orchestrates state synchronization through the `rulesAreInContext` and `syncContext` functions (lines 34-59). The extension triggers this synchronization on critical lifecycle events: `session_start`, `session_tree`, and `session_compact` (lines 37-40).

Using the boolean result from `latestMarkerIsActive`, the extension decides whether to inject or withdraw rules:

- **When enabled but inactive**: The extension calls `pi.sendMessage` with `customType: RULES_MESSAGE_TYPE` to inject the ADHD formatting guidelines.
- **When disabled but active**: The extension sends a message with `customType: DISABLED_MESSAGE_TYPE` to explicitly mark the rules as withdrawn.

This bidirectional synchronization ensures the context always reflects the user's current preference regarding ADHD accommodations.

## Why the Latest Marker Matters

Conversation contexts in Pi undergo periodic compaction to remove older entries and manage memory usage. During `session_compact` events, earlier messages—including previously injected rules—may be dropped from the active context.

By always evaluating the **latest** marker rather than counting total occurrences, the extension guarantees that stale rulesets are never left orphaned in a compacted context without a corresponding disabled marker. The linear scan approach is computationally inexpensive because conversation contexts typically remain small, making this check efficient enough to run on every relevant lifecycle event.

## Implementation Example

The following TypeScript implementation demonstrates how to verify whether ADHD rules are currently active using the utilities from [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts). This pattern mirrors the logic used internally by the extension to determine when to inject or withdraw formatting guidelines.

```typescript
import { contextMessages, latestMarkerIsActive } from "./extensions/context-compat";

const RULES_MESSAGE_TYPE = "i-have-adhd-rules";
const DISABLED_MESSAGE_TYPE = "i-have-adhd-disabled";

function areRulesActive(sessionManager: unknown): boolean {
  const messages = contextMessages(sessionManager);
  return latestMarkerIsActive(
    messages,
    RULES_MESSAGE_TYPE,
    DISABLED_MESSAGE_TYPE
  );
}

```

The extension's internal synchronization logic uses this pattern within `syncContext` to maintain state:

```typescript
function syncContext(ctx: ExtensionContext) {
  const rulesActive = areRulesActive(ctx.sessionManager);
  
  if (enabled && !rulesActive) {
    pi.sendMessage({ 
      customType: "i-have-adhd-rules", 
      content: RULES_HEADER + "\n\n" + rules, 
      display: false 
    });
  } else if (!enabled && rulesActive) {
    pi.sendMessage({ 
      customType: "i-have-adhd-disabled", 
      content: DISABLED_NOTICE, 
      display: false 
    });
  }
}

```

## Summary

- The **latestMarkerIsActive** function in [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts) performs a chronological scan of conversation messages to determine whether ADHD rules are currently injected.
- **contextMessages** provides defensive abstraction over Pi's session manager API, returning empty arrays on failure to prevent crashes.
- The scan logic treats `RULES_MESSAGE_TYPE` as activating and `DISABLED_MESSAGE_TYPE` as deactivating, with the final marker in the sequence determining the current state.
- Synchronization occurs on `session_start`, `session_tree`, and `session_compact` events to maintain consistency across conversation lifecycle changes.
- Tracking the **latest** marker specifically prevents state desynchronization when older context entries are removed during compaction.

## Frequently Asked Questions

### How does latestMarkerIsActive handle missing or corrupted session data?

The `contextMessages` wrapper function ensures resilience by attempting multiple API methods (`buildSessionContext().messages` and `buildContextEntries()`) and catching any thrown exceptions. If the session manager is unavailable or returns unexpected structures, `contextMessages` returns an empty array, causing `latestMarkerIsActive` to return `false` by default rather than throwing errors.

### What happens when both marker types appear in the conversation history?

When both `RULES_MESSAGE_TYPE` and `DISABLED_MESSAGE_TYPE` markers exist in the context, the **chronological order** determines the outcome. The function processes messages sequentially, updating an internal boolean flag each time it encounters either marker type. Only the final occurrence of either marker influences the return value, effectively canceling out any previous state changes.

### Why scan the entire message array instead of checking only the last message?

While the function could theoretically check only the final message, scanning the entire array ensures compatibility with conversation compaction and tree restructuring events where messages might be reordered or intermediate markers added. The linear scan from [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts) (lines 48-58) is computationally trivial for typical context sizes and guarantees accurate state detection regardless of message ordering complexities.

### When exactly does the extension inject or withdraw the ADHD rules?

The extension triggers synchronization via `syncContext` on three specific Pi lifecycle events: `session_start` (new conversation), `session_tree` (conversation branching), and `session_compact` (context cleanup). During each trigger, if `latestMarkerIsActive` returns `false` but the rules are enabled in settings, the extension injects them; conversely, if it returns `true` but rules are disabled, it sends a withdrawal marker.