# pi-role

<p align="center">
  <img src="https://raw.githubusercontent.com/arcanemachine/pi-role/main/logo.jpg" alt="Pi mascot choosing a role from a wardrobe" width="250" />
</p>

A thin role extension for [Pi](https://pi.dev). Activate a Markdown role for the current session (e.g. architect, worker, etc.) without changing its model, thinking level, tools, or name.

`pi-role` ships no roles. User and project role files are discovered at runtime.

## Features

- `/role` command with role-key autocomplete
- `--role <key>` startup selection
- Project roles override user roles
- Configurable project roles directory
- Active role body appended to Pi's upstream system prompt
- Durable, branch-aware role state across resume, reload, fork, and clone
- Compact, standard informational role-change entries that are not sent to the model
- No default role and no status text while inactive

## Install

From GitHub:

```bash
pi install git:github.com/arcanemachine/pi-role
```

From npm (after publication):

```bash
pi install npm:@arcanemachine/pi-role
```

For local development:

```bash
pi -e ./src/index.ts
```

## Role files

User roles live in:

```text
~/.pi/agent/roles/
```

Project roles default to:

```text
<project>/.pi/roles/
```

The filename basename is the role key. For example, `architect.md` is activated with `/role architect`. Keys are matched case-insensitively. Project roles override user roles with the same key.

The keys `list`, `current`, `reload`, and `none` are reserved by the command.

A role uses YAML frontmatter followed by its system-prompt body:

```markdown
---
name: "Architect"
description: Plans architecture and defines implementation boundaries.
meta:
  team: platform
---

You are the Architect. Define boundaries and decisions before implementation.
```

Frontmatter fields:

| Field         | Required | Purpose                                                         |
| ------------- | -------- | --------------------------------------------------------------- |
| `name`        | yes      | Unconstrained printed name used in notices and status text      |
| `description` | yes      | Short description shown by `/role`                              |
| `meta`        | no       | Open metadata object reserved for future use; currently ignored |

Other frontmatter fields are tolerated and ignored. Frontmatter is never added to the model prompt.

## Project configuration

Set `pi-role.rolesDir` in `<project>/.pi/settings.json` to use another project-relative directory:

```json
{
  "pi-role": {
    "rolesDir": ".agents/roles"
  }
}
```

Relative paths resolve from Pi's current project directory (`ctx.cwd`). Absolute paths are also accepted.

Project settings and roles follow Pi's native project-trust result. A bare `.pi/roles` directory does not itself trigger Pi's trust prompt; activating a role is always explicit because there is no default role.

## Commands

| Command         | Behavior                                          |
| --------------- | ------------------------------------------------- |
| `/role`         | List effective roles                              |
| `/role list`    | List effective roles                              |
| `/role <key>`   | Activate a role, or reload it when already active |
| `/role current` | Show the active role and source file              |
| `/role reload`  | Re-read the active role from disk                 |
| `/role none`    | Disable the active role                           |

Activating a role adds a compact user-visible entry:

```text
Role type switched to Architect.
```

The status bar receives the exact string `Role: Architect 👤 `, including one trailing space after the emoji.

`/role none` clears the status, adds `Role type disabled.` to the transcript, removes the role body from later system prompts, and adds a hidden context message telling the agent to stop following the removed role.

## CLI flag

```bash
pi --role architect
```

The flag applies on initial process startup and overrides restored role state. It does not become a default for later `/new` sessions. An unknown key reports an error and starts without a role.

## Session behavior

- New sessions start without a role.
- Resume and extension reload restore the latest explicit role state silently.
- Fork and clone inherit the role state copied with their session branch.
- Restoring or reloading re-reads the role file from disk.
- Missing or invalid restored roles leave the session inactive without selecting a fallback.

## Prompt behavior

For every agent invocation while a role is active, the extension composes:

```text
<complete upstream Pi system prompt>

<active role Markdown body>
```

This preserves Pi's default prompt, project context, skills, and changes made by earlier extensions. Switching roles does not trigger a model turn.

## Development

```bash
npm install
npm run typecheck
npm run test
npm run build
npm run format
npm pack --dry-run
```

The package is source-loaded by Pi from `src/index.ts`; no compiled runtime artifact is required for publication.

## License

MIT. See [LICENSE.md](./LICENSE.md).
