---
slug: "pi-context-loader"
source_type: "readme"
source_url: "https://cdn.jsdelivr.net/gh/juanje/pi-context-loader@main/README.md"
repo: "https://github.com/juanje/pi-context-loader"
source_file: "README.md"
branch: "main"
---
# pi-context-loader

Config-driven context injection for [Pi](https://pi.dev) agents. Loads files at session start and injects them as system prompt or message — the Pi equivalent of a `sessionStart` hook.

## Install

From npm:

```bash
pi install npm:pi-context-loader
```

From git:

```bash
pi install git+https://github.com/juanje/pi-context-loader.git
```

Or load directly without installing:

```bash
pi -e /path/to/pi-context-loader/extensions/context-loader.ts
```

## Quick start

Create `.pi/context-loader.json` in your project:

```json
{
  "files": [
    "context/user-profile.md",
    "context/current-state.md"
  ]
}
```

Start Pi — the listed files are read at session start and injected into the agent's context (system prompt by default, or as a message with `"inject": "message"`).

## How it works

The extension hooks into two Pi events:

1. **`session_start`** — loads the config, reads all listed files and optional latest log, caches the combined context
2. **`before_agent_start`** — injects the cached context via the configured mode

### Injection modes

The `inject` field controls how context reaches the agent:

| Mode | Behavior | Frequency | Survives compaction | LLM weight |
|------|----------|-----------|-------------------|------------|
| `"systemPrompt"` (default) | Appended to system prompt | Every turn | Yes — always present | High — treated as instructions |
| `"message"` | Injected as a conversation message | Once — first turn only | No — may be summarized | Normal — treated as context |

**Why the frequency differs:** the system prompt is rebuilt fresh on every turn, so it must be re-appended each time or it would disappear. A message, once added, becomes a permanent part of conversation history — re-injecting it on every turn would just duplicate the same content across the transcript instead of refreshing anything (the file content itself is only read once, at `session_start`, either way).

**When to use each:**
- **`systemPrompt`** — for identity, rules, or context that must be present on every turn (e.g., user profile, agent guidelines)
- **`message`** — for operational state that's useful at the start of the session but shouldn't be duplicated turn after turn (e.g., active incidents, current sprint items)

## Config format

Config file: `.pi/context-loader.json`

```typescript
interface ContextLoaderConfig {
  files?: string[];        // paths relative to project root
  latestLog?: {
    index: string;         // path to an index file (e.g. "logs/index.md")
    dir: string;           // directory containing log files (e.g. "logs")
    marker: string;        // marker to match in index lines (e.g. "active")
  };
  separator?: string;      // join string (default: "\n\n---\n\n")
  inject?: "systemPrompt" | "message";  // injection mode (default: "systemPrompt")
}
```

### `files`

Array of file paths relative to the project root. Each file is read and its content is included in the context. Missing files are silently skipped.

### `latestLog`

Optional dynamic log finder. Scans the `index` file for lines matching `marker` (case-insensitive), extracts the last `YYYY-MM-DD` date found, and loads `{dir}/{date}.md`.

Useful for agents with session logs where you want to inject the most recent active log automatically.

### `separator`

String used to join all loaded content. Defaults to `"\n\n---\n\n"` (markdown horizontal rule).

### `inject`

How context is delivered to the agent. Either `"systemPrompt"` (default) or `"message"`. See [Injection modes](#injection-modes) for details.

## Examples

### Memory agent ([Agentic Buddy](https://github.com/juanje/agentic-buddy)-style)

```json
{
  "files": [
    "agent_brain/identity/USER.md"
  ],
  "latestLog": {
    "index": "logs/index.md",
    "dir": "logs",
    "marker": "active"
  }
}
```

### Diagnostic agent (active incidents as message)

```json
{
  "files": ["kb/active/index.md"],
  "inject": "message"
}
```

### Diagnostic agent (reference context in system prompt)

```json
{
  "files": [
    "context/team-roster.md",
    "context/known-issues-summary.md"
  ]
}
```

### Minimal

```json
{
  "files": ["CONTEXT.md"]
}
```

## Static context

This extension handles **dynamic** context — files that change between sessions. For static context, Pi has built-in support:

- **`.pi/SYSTEM.md`** — replaces the default system prompt (agent identity)
- **`AGENTS.md` / `CLAUDE.md`** — hierarchical context files loaded automatically

Use `pi-context-loader` for content that needs to be assembled from multiple files or includes dynamic elements like "latest active log."

## Development

```bash
git clone https://github.com/juanje/pi-context-loader.git
cd pi-context-loader
npm install
npm run check    # typecheck + lint + test
```

## License

MIT — see [LICENSE](https://github.com/juanje/pi-context-loader/tree/HEAD/LICENSE).
