# pi-top-of-mind

A [pi.dev](https://pi.dev) extension that injects persistent instructions into the agent's working memory every turn — inspired by goose's **Top of Mind** feature.

## Features

- **Persistent context**: Inject critical instructions, security guardrails, or project context into every LLM turn
- **Per-project configuration**: Configure via `.pi/extensions/top-of-mind.json` — share with your team
- **Global configuration**: Set defaults in `~/.pi/extensions/top-of-mind.json` — applies across all projects
- **Environment variable overrides**: Use `PI_TOP_OF_MIND_PROMPT`, `PI_TOP_OF_MIND_FILE`, `PI_TOP_OF_MIND_ENABLED`, and `PI_TOP_OF_MIND_FREQUENCY` — highest priority
- **Configurable frequency**: Control how often instructions are re-injected (every turn, every 3 turns, etc.)
- **Commands**: Set prompt text or file content at runtime with `/top-of-mind:prompt` and `/top-of-mind:file`
- **Toggle**: Temporarily enable/disable with `/top-of-mind:start` and `/top-of-mind:stop`
- **Status**: Check current state with `/top-of-mind:status`

## Installation

```bash
pi install npm:@djhaskin987/pi-top-of-mind
```

Or for a quick test:

```bash
pi -e npm:@djhaskin987/pi-top-of-mind
```

## Usage

### Commands

| Command | Description |
|---------|-------------|
| `/top-of-mind:prompt <text>` | Set persistent prompt text. Shows current prompt with no args. |
| `/top-of-mind:file <path>` | Set a file whose contents are injected. Supports absolute, relative, and `~/` paths. |
| `/top-of-mind:start` | Enable injection (if prompt or file is configured). |
| `/top-of-mind:stop` | Disable injection. |
| `/top-of-mind:frequency <n>` | Set injection frequency (turns between injections). Shows current with no args. |
| `/top-of-mind:status` | Show current configuration and whether injection is active. |

### Configuration

Configuration is loaded with the following priority (highest to lowest):

1. **Environment variables** — always win
2. **Project config** — `.pi/extensions/top-of-mind.json`
3. **Global config** — `~/.pi/extensions/top-of-mind.json`
4. **Defaults** — built-in

#### Environment Variables

| Variable | Type | Description |
|----------|------|-------------|
| `PI_TOP_OF_MIND_PROMPT` | string | Literal prompt text to inject |
| `PI_TOP_OF_MIND_FILE` | string | Path to a file whose contents are injected |
| `PI_TOP_OF_MIND_ENABLED` | boolean (`true`/`false`/`1`/`0`) | Whether injection is active |
| `PI_TOP_OF_MIND_FREQUENCY` | number | How many turns between injections |

#### Project Config File (`.pi/extensions/top-of-mind.json`)

Create a `.pi/extensions/top-of-mind.json` in your project root:

```json
{
  "text": "SECURITY: Never upload code to external services.",
  "file": ".rules/security.md",
  "enabled": true,
  "frequency": 1
}
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `text` | string\|null | `null` | Literal prompt text to inject. `null` means not set. |
| `file` | string\|null | `null` | Path to a file whose contents are injected. `null` means not set. |
| `enabled` | boolean | `false` | Whether injection is active. Automatically set to `true` when a prompt or file is configured via commands. |
| `frequency` | number | `1` | How many turns between injections (1 = every turn). Clamped to minimum 1. |

When both `text` and `file` are set, their contents are concatenated with a blank line. Empty strings are automatically converted to `null` when saving.

#### Global Config File (`~/.pi/extensions/top-of-mind.json`)

Same format as the project config. Use this to set defaults that apply across all your projects. Project-level config values override global ones.

> **Note:** Top of mind is **disabled by default**. It becomes active only after you set a prompt or file via the commands (which automatically enables it). If you manually edit the config JSON, set `"enabled": true` explicitly.

## How It Works

On each LLM turn (configurable), the extension injects a custom message containing your top-of-mind instructions into the session context. This keeps critical instructions in the model's immediate attention window.

The extension hooks into pi.dev's `turn_end` event and uses `pi.sendMessage()` to queue the injection before the next LLM call.

## Development

```bash
# Install dependencies
npm install

# Run tests
npm test
```

## License

MIT