# What Is the `session_compact` Process in the i-have-adhd Extension and Why It Prevents Lost Context

> Understand the session_compact process in the i-have-adhd extension. Learn how this crucial event preserves ADHD response rules during conversation history compression to prevent lost context.

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

---

**The `session_compact` event is a Pi runtime hook that triggers whenever conversation history is compressed, and the i-have-adhd extension uses it to re-inject ADHD response rules if they get removed during compaction.**

The `session_compact` mechanism is critical for any Pi extension that injects custom messages into the model's context. In the `ayghri/i-have-adhd` repository, this hook ensures that the 10 ADHD-friendly response rules survive session compression cycles. Without this safeguard, the extension's core functionality would silently break mid-session as the runtime drops older messages to manage context size.

## How `session_compact` Works in the Pi Runtime

The Pi runtime periodically compacts session history to keep memory usage bounded. During compaction, the runtime may summarize or drop older messages—including custom markers injected by extensions. The `session_compact` event fires after this process completes, giving extensions a chance to restore any lost state.

According to the source code in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts), the extension registers for this event at line 221:

```typescript
pi.on("session_compact", async (_event, ctx) => syncContext(ctx));

```

This one-line handler delegates to `syncContext`, which implements the full re-synchronization logic.

## Why Compaction Threatens Extension State

The i-have-adhd extension operates by prepending a ruleset to the model's context. The rules are defined in [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) and injected as a hidden message with `customType: RULES_MESSAGE_TYPE`. The compaction process poses two specific risks:

- **Ruleset removal** – Older messages, including the injected rules, may be dropped entirely
- **Stale markers** – A disabled notice or ruleset from a previous state may persist incorrectly

The extension cannot rely on a one-time injection because the runtime's compaction is opaque and can occur at any point during a long conversation.

## The `syncContext` Re-Synchronization Strategy

The `syncContext` function in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) implements idempotent context repair. It follows a precise algorithm to ensure correct state without duplicate injections.

### Step 1: Retrieve Current Context Messages

The function calls `contextMessages(ctx.sessionManager)` to get the actual message list after compaction. This helper is defined in [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts).

### Step 2: Check Latest Marker Status

The `latestMarkerIsActive` function (lines 41-61 in [`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts)) scans messages to determine if the most recent custom marker is:
- The `RULES_MESSAGE_TYPE` marker (rules active)
- The `DISABLED_NOTICE_TYPE` marker (rules explicitly disabled)
- No marker (clean state)

### Step 3: Inject or Correct as Needed

Based on the enabled state and marker presence, `syncContext` takes one of three actions:

- **Enabled + missing rules**: Re-inject the full ruleset
- **Disabled + stale rules present**: Inject `DISABLED_NOTICE` to cancel prior rules
- **Already correct**: No-op to avoid duplicates

The re-injection code at lines 121-129 shows the exact message structure:

```typescript
pi.sendMessage(
  {
    customType: RULES_MESSAGE_TYPE,
    content: `${RULES_HEADER}\n\n${rules}`,
    display: false,
  },
  { triggerTurn: false },
);

```

The `display: false` ensures the message remains hidden from the user interface, while `triggerTurn: false` prevents the re-injection from causing an unwanted model response.

## Real-World Scenario: Rules Persistence Across Compaction

Consider a user who enables ADHD mode early in a conversation:

```typescript
// User executes the slash command
/i-have-adhd

// Extension sets state and injects initial rules
enabled = true;
// ruleset injected as hidden message

```

After many turns, the Pi runtime compacts the session:

```typescript
// Runtime internal: drops messages beyond context window
// → ADHD ruleset message is removed
// → session_compact event fires
// → syncContext detects missing RULES_MESSAGE_TYPE
// → ruleset re-injected automatically

```

The user experiences uninterrupted ADHD-friendly responses despite the compaction.

## Handling Mode Cancellation

The same mechanism handles graceful shutdown. When a user says "stop adhd mode":

```typescript
if (enabled && STOP_PHRASES.has(input)) {
  setEnabled(false, ctx);
}

```

On next compaction:

```typescript
// syncContext sees: enabled=false, but RULES_MESSAGE_TYPE still present
// → injects DISABLED_NOTICE which supersedes prior rules
// → future compactions see DISABLED_NOTICE as latest marker, no further action

```

This ensures the conversation reverts to standard behavior without ghost rules affecting model outputs.

## Debugging Context State

Developers can inspect the current marker status using exported helpers from [`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts):

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

const msgs = contextMessages(ctx.sessionManager);
const status = latestMarkerIsActive(
  msgs,
  "i-have-adhd-rules",      // RULES_MESSAGE_TYPE
  "i-have-adhd-disabled",    // DISABLED_NOTICE_TYPE
);
console.log(`Marker active: ${status}`);

```

This returns `true` if either marker is present and is the most recent custom type, `false` otherwise.

## Summary

- **`session_compact`** is a Pi runtime event fired after conversation history compression
- The handler **`syncContext`** re-synchronizes injected ADHD rules if compaction removed them
- **`latestMarkerIsActive`** provides idempotency by checking the most recent marker before injection
- The extension maintains **continuity** across unlimited compaction cycles without duplicate messages
- **Graceful disabling** works by injecting a cancellation notice that overrides prior rules

## Frequently Asked Questions

### What triggers the `session_compact` event in Pi?

The Pi runtime triggers `session_compact` automatically when the conversation context exceeds internal size thresholds. This occurs transparently during long chat sessions and may involve summarizing or dropping older messages. The event has no fixed interval—it fires as needed based on runtime memory management heuristics.

### How does the extension avoid injecting duplicate rules?

The `latestMarkerIsActive` function in [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts) scans the current message list and returns `true` only if the most recent custom marker matches the expected type. Before any injection, `syncContext` verifies whether the correct marker is already present. If present, no action is taken; if absent or stale, the appropriate correction is applied.

### Can users disable ADHD mode permanently without compaction occurring?

Yes. The `setEnabled(false, ctx)` function immediately injects the `DISABLED_NOTICE` marker through `syncContext`, so the disabled state takes effect before any compaction. Subsequent compactions simply confirm the `DISABLED_NOTICE` marker remains the latest, requiring no additional changes. The mechanism works correctly regardless of when compaction occurs.

### Where are the actual ADHD rules stored in the repository?

The 10 response rules live in [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md). The extension loads this file at initialization and stores the content in the `rules` variable. When injection is required, the rules are wrapped with `RULES_HEADER` and sent as the content field of a hidden message with `customType: "i-have-adhd-rules"`.