# How `syncContext` Manages Context Injection Across User Sessions in the i-have-adhd Extension

> Learn how the syncContext function in the i-have-adhd extension injects context across user sessions. It ensures isolated, up-to-date state for each user with stateless skill implementations.

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

---

**The `syncContext` function synchronizes per-session `ExtensionContext` objects into a global `ContextStore` through shallow merging, ensuring isolated, up-to-date conversational state for each user while keeping skill implementations stateless.**

The `syncContext` function sits at the heart of the **ayghri/i-have-adhd** extension's session management architecture. Located in [[`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts)](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts), this utility bridges the gap between the host runtime's ephemeral session objects and the persistent context that ADHD-friendly skills need to deliver personalized responses.

## How `syncContext` Handles Context Injection

### Core Merging Logic

At lines **118-130** of the extension file, `syncContext` performs a shallow merge of incoming session data into the global `ContextStore`:

```typescript
// extensions/i-have-adhd.ts – syncContext implementation
const syncContext = (ctx: ExtensionContext): void => {
  // Grab the current session's context object
  const incoming = ctx.context ?? {};

  // Merge into the global store that skills read from
  for (const [key, value] of Object.entries(incoming)) {
    if (value !== undefined) {
      ContextStore[key] = value;   // shallow overwrite
    }
  }
};

```

This design prioritizes **performance and simplicity**: only defined values are copied, and existing keys are overwritten in-place rather than triggering deep cloning operations.

### Session Initialization Hook

The function first executes during extension activation at lines **152-159**, capturing the initial `ExtensionContext` passed by the host runtime:

```typescript
// Called at end of activate routine
export const activate = async (ctx: ExtensionContext) => {
  // ... setup code ...
  syncContext(ctx);  // Prime the ContextStore with session baseline
};

```

This early injection ensures that skills have immediate access to user profile data, preferences, and any persisted state from previous interactions.

## Event-Driven Context Synchronization

### The `session_compact` Listener

The extension registers a runtime event handler at lines **221-226** to maintain synchronization as sessions evolve:

```typescript
// Hook the host runtime to keep the store fresh
pi.on("session_compact", async (_event, ctx) => syncContext(ctx));

```

**`session_compact`** fires when the host runtime compresses or truncates a session—typically after message volume thresholds are crossed. Without this hook, the `ContextStore` would retain stale references to truncated message history or outdated metadata.

### Why Event-Driven Updates Matter

- **Memory pressure handling**: Large conversations get compacted transparently; `syncContext` propagates the reduced context without skill intervention
- **Metadata freshness**: Session timestamps, token counts, and truncation markers stay current
- **Zero skill coupling**: Skills read from `ContextStore` without awareness of runtime garbage collection events

## Session Isolation Guarantee

Each user session receives a distinct `ExtensionContext` instance. The `syncContext` function's architecture ensures isolation through three mechanisms:

1. **Per-session activation**: Every new session triggers a fresh `activate()` call with its own `ctx` parameter
2. **Overwrite semantics**: The shallow merge replaces rather than accumulates, preventing cross-session data leakage
3. **Runtime-enforced boundaries**: The host guarantees `ExtensionContext` objects never span multiple users

## Consumption by ADHD-Friendly Skills

The synchronized context flows to skill implementations through `ContextStore` reads. The skill definition in [[`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md)](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) accesses this data to:

- Recall user-specified "focus" topics for attention management
- Apply preferred response formats (bullet points, structured summaries)
- Maintain continuity across session compactions

This **separation of concerns** keeps skills pure and testable while the extension handles all session bookkeeping.

## Key Files and Their Roles

| File | Purpose | Critical Lines |
|------|---------|--------------|
| [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) | Defines `syncContext`, activation hooks, and event registration | 118-130, 152-159, 221-226 |
| [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) | Consumes `ContextStore` for personalized response generation | Skill implementation details |
| [`hooks/hooks.json`](https://github.com/ayghri/i-have-adhd/blob/main/hooks/hooks.json) | Declares `session_compact` as an always-on hook for this extension | Hook manifest |
| [`README.md`](https://github.com/ayghri/i-have-adhd/blob/main/README.md) | Documents extension loading and high-level architecture | Repository overview |

## Summary

- **`syncContext`** performs shallow merges of `ExtensionContext` into `ContextStore` at [`extensions/i-have-adhd.ts:118-130`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts#L118-L130)
- **Dual invocation pattern**: runs once at session start (lines 152-159) and on every `session_compact` event (lines 221-226)
- **Session isolation** is enforced through per-session `ExtensionContext` instances and overwrite-based merging
- **Zero-overhead design** skips undefined values and avoids deep cloning
- **Skill decoupling** lets ADHD-friendly response logic remain stateless while accessing rich contextual data

## Frequently Asked Questions

### What triggers `syncContext` to run besides session startup?

The `session_compact` event triggers additional executions. This event fires when the host runtime compresses conversation history to manage memory, ensuring the `ContextStore` reflects truncated message lists and updated metadata rather than stale references.

### How does `syncContext` prevent user data from leaking between sessions?

Each session receives its own `ExtensionContext` instance from the host runtime. The `syncContext` function overwrites `ContextStore` entries rather than appending to them, and the host runtime never shares context objects across users. The activation hook runs fresh for every new session.

### Why does `syncContext` use shallow merging instead of deep cloning?

Shallow merging minimizes CPU overhead during high-frequency `session_compact` events. Since the `ExtensionContext` structure consists primarily of primitive values and flat objects at the top level, deep cloning would add unnecessary cost without practical benefit for this use case.

### Where do skills actually read the synchronized context?

Skills access context data through reads on the global `ContextStore` object. The skill implementation in [[`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md)](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) pulls user preferences and session state from this store to tailor ADHD-friendly response formatting, without directly interacting with the extension's synchronization logic.