{"_id":"@andywangzzm/pi-roles","name":"@andywangzzm/pi-roles","dist-tags":{"latest":"0.2.3"},"versions":{"0.2.3":{"name":"@andywangzzm/pi-roles","version":"0.2.3","description":"Role-based session configuration for pi coding agent. Launch a session as a named role and hot-swap roles mid-session, with optional pi-intercom and pi-mcp-adapter integration.","keywords":["pi-package","pi","pi-extension","role","roles","session","agent","system-prompt"],"license":"MIT","type":"module","main":"./dist/index.js","exports":{".":"./dist/index.js"},"types":"./dist/index.d.ts","pi":{"extensions":["./dist/index.js"]},"peerDependencies":{"@mariozechner/pi-agent-core":"*","@mariozechner/pi-ai":"*","@mariozechner/pi-coding-agent":"*","@mariozechner/pi-tui":"*","typebox":"*"},"peerDependenciesMeta":{"@mariozechner/pi-coding-agent":{"optional":false},"@mariozechner/pi-agent-core":{"optional":false},"@mariozechner/pi-ai":{"optional":false},"@mariozechner/pi-tui":{"optional":true},"typebox":{"optional":false}},"dependencies":{"yaml":"^2.5.0"},"devDependencies":{"@mariozechner/pi-ai":"*","@mariozechner/pi-coding-agent":"*","tsup":"^8.5.1","typebox":"^1.0.0","typescript":"^5.5.0","vitest":"^2.0.0"},"scripts":{"build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit","prepublishOnly":"npm run clean && npm run build && npm run typecheck","test":"vitest run","test:watch":"vitest","publish:token":"export $(grep -v '^#' .env | xargs) && npm publish --access public"},"engines":{"node":">=20"},"_id":"@andywangzzm/pi-roles@0.2.3","gitHead":"8fd17c72efdf30b68874979d4e73f634164c89c5","_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-pbAtVqQoeKNV2c4BUxPBwThE8KW7UFxaNGDoyzNaLODrviI5IBxT1VFoaBn6+M5O46oZeIFQ0KWm3MdCFTffqw==","shasum":"4c415d1ca5869c69d071bd1e10901c78afb9441f","tarball":"https://registry.npmjs.org/@andywangzzm/pi-roles/-/pi-roles-0.2.3.tgz","fileCount":9,"unpackedSize":75572,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCJace9wry1T17dNP40/yEfqU1yo9gEzmb7gS5RJHhqSwIhAKOQq1XAn1fbhOjV7MBBUnXwGsYK7u5n6wVOzkGgQwnF"}]},"_npmUser":{"name":"andywangzzm","email":"andywang646691@gmail.com"},"directories":{},"maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pi-roles_0.2.3_1786723692868_0.8398950011223651"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-14T16:08:12.696Z","0.2.3":"2026-08-14T16:08:13.014Z","modified":"2026-08-14T16:08:13.328Z"},"maintainers":[{"name":"andywangzzm","email":"andywang646691@gmail.com"}],"description":"Role-based session configuration for pi coding agent. Launch a session as a named role and hot-swap roles mid-session, with optional pi-intercom and pi-mcp-adapter integration.","keywords":["pi-package","pi","pi-extension","role","roles","session","agent","system-prompt"],"license":"MIT","readme":"# pi-roles\n\n> Role-based session configuration for [pi coding agent](https://github.com/badlogic/pi-mono). Launch a session as a named role (architect, planner, marketing-strategist, …) and hot-swap roles mid-session — without restarting Pi.\n\n`pi-roles` is to **top-level pi sessions** what [`pi-subagents`](https://github.com/nicobailon/pi-subagents) is to **sub-agents**: same `.md` + YAML frontmatter convention, same project/user scope rules, drop-in flow. The extension is **agnostic of which roles exist** — roles are just markdown files you create.\n\n```bash\npi --role architect              # launch as architect\nPI_ROLE=planner pi               # or via env\n\n/role list                       # inside the session\n/role planner                    # swap role mid-session, keep history\n/role planner --reset            # swap role and clear history\n/role current\n/role reload                     # re-read the active role file from disk\n```\n\nWhen you swap roles, the session's **system prompt, model, thinking level, and active tool set** are replaced according to the new role's definition. Conversation history is preserved by default.\n\n---\n\n## Install\n\n```bash\npi install npm:@andywangzzm/pi-roles\n```\n\nThen restart pi. The extension is auto-discovered; the `--role` flag and `/role` command become available.\n\nTo try without installing:\n\n```bash\npi -e git:github.com/andywang646691/pi-roles\n```\n\n---\n\n## Why this exists\n\nWhen you build a multi-agent dev workflow with specialized roles — architect (design), planner (decompose), orchestrator (dispatch), or any equivalent for marketing, research, ops — the *top-level* role is a property of the whole session, not of an individual sub-agent dispatch. You want different system prompts, different models, different tool restrictions per role, and you want to switch between them without restarting.\n\n`pi-roles` is the cleanest way to do that. No shell aliases, no separate workspace directories, no forking pi-subagents into something it isn't.\n\n---\n\n## Role files\n\nRoles are markdown files with YAML frontmatter, identical in shape to `pi-subagents` agent files:\n\n```markdown\n---\nname: architect\ndescription: Defines the WHAT. Owns architecture and specs. Never codes.\nmodel: anthropic/claude-opus-4-7\nthinking: high\ntools: read, grep, find, ls, write, edit\nintercom: send             # optional, per-role override\nextends: base-reviewer     # optional, role inheritance\n---\n\n# Role\n\nYou are the Architect. Your job is to define WHAT the system should\ndo, never HOW to build it...\n\n(everything below the frontmatter is the system prompt body)\n```\n\n### Frontmatter reference\n\n| Field | Required | Behavior when omitted |\n|---|---|---|\n| `name` | yes | — must match the filename without `.md` |\n| `description` | yes | — shown in `/role list` and selectors |\n| `model` | no | keeps the session's current model |\n| `thinking` | no | keeps the session's current thinking level (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`) |\n| `tools` | no — see below | inherits from parent (if `extends`) or keeps current active set |\n| `intercom` | no | falls back to the global `intercomMode` setting |\n| `extends` | no | role inherits from another role |\n\n#### `tools` — the tri-state\n\nThree explicit states with three different meanings:\n\n| YAML | Meaning |\n|---|---|\n| `tools: read, bash` | **set** — exactly these tools, nothing else |\n| `tools:` (present, empty) | **disable all tools** — read-only conversation, no actions |\n| field absent | **inherit** — from parent role (`extends`), else keep session default |\n\nYou can also include MCP tool refs in the same field, mirroring `pi-subagents`:\n\n```yaml\ntools: read, grep, mcp:chrome-devtools, mcp:github\n```\n\n`mcp:server-name` entries require [`pi-mcp-adapter`](https://github.com/nicobailon/pi-mcp-adapter) to be installed. If it's not, the entry is logged and skipped — the role still loads.\n\n#### `model` — provider/id format\n\nMatches Pi's CLI `--model` syntax:\n\n```yaml\nmodel: anthropic/claude-opus-4-7\nmodel: openai/gpt-5\nmodel: deepseek/deepseek-v4-pro\n```\n\nIf the model isn't available (no API key, unknown provider), the role load surfaces a warning and the session keeps its current model.\n\n#### `intercom` — per-role override\n\nValues: `off`, `receive`, `send`, `both`. Defaults to the global `intercomMode` setting (which itself defaults to `off`). See [pi-intercom integration](#pi-intercom-integration) below.\n\n#### `extends` — role inheritance\n\n```yaml\nextends: architect\n```\n\nA child role inherits everything from its parent and overrides selectively. Chains are supported (`A extends B extends C`); cycles are detected at load time and produce a hard error.\n\n**Merge rules:**\n\n- `model`, `thinking`, `description`, `intercom`: child wins if set, else parent value.\n- `tools`: see the tri-state above. **Set overrides; empty disables; absent inherits.**\n- Markdown body: parent's body is **prepended** to child's body with a separator. Useful for \"stricter variant\" patterns (`architect-strict extends architect`).\n- `name`: never inherited — always the child's own filename.\n\n---\n\n## Discovery\n\nRoles are looked up in this order, **first match wins** for any given name:\n\n| Scope | Path | Marker in `/role list` |\n|---|---|---|\n| project | `<repo>/.pi/roles/<name>.md` (or any ancestor) | `[project]` |\n| user | `~/.pi/agent/roles/<name>.md` | `[user]` |\n| built-in | bundled with the package | `[built-in]` |\n\nWhen a project-scope role shadows a user-scope role of the same name, the user-scope entry is listed under a separate \"Shadowed\" heading in `/role list` output so you know it exists but won't load.\n\nThe default `roleScope` is `both` (project + user + built-in). Override via settings:\n\n```json\n// ~/.pi/agent/settings.json\n{\n  \"pi-roles\": {\n    \"roleScope\": \"both\",        // \"user\" | \"project\" | \"both\"\n    \"defaultRole\": \"architect\", // optional; falls back to role-assistant\n    \"intercomMode\": \"off\",      // \"off\" | \"receive\" | \"send\" | \"both\"\n    \"titleModel\": \"openai/gpt-4o-mini\"\n  }\n}\n```\n\n---\n\n## Built-in `role-assistant`\n\n`pi-roles` ships **one** built-in role: `role-assistant`. It's the default fallback when no `defaultRole` is configured and you don't pass `--role` or `PI_ROLE`.\n\nThe role-assistant:\n\n1. Lists the roles available on your machine (project + user + built-in) on its first turn.\n2. Shows the exact command to switch to one (e.g. `/role architect`).\n3. Offers to help you build a **new** role: it asks the questions, drafts the markdown, shows it for your approval, writes it to project or user scope (your choice), and then prints the command for you to launch it (`/role <new-name> --reset`).\n\nYou can override the built-in by dropping a `role-assistant.md` into your project or user roles directory — the same priority rules apply.\n\nYou can also set any other role as your default:\n\n```json\n{ \"pi-roles\": { \"defaultRole\": \"architect\" } }\n```\n\nIf `defaultRole` points to a missing role, the built-in `role-assistant` is used and a warning is shown.\n\n---\n\n## Slash command\n\n`/role <subcommand>` — Tab-completes role names against the current scope.\n\n| Form | Behavior |\n|---|---|\n| `/role <name>` | Switch to `<name>`. **Preserves history.** Re-reads the file from disk (no caching). |\n| `/role <name> --reset` | Switch to `<name>` **and** clear history (equivalent to `/new` + apply role). |\n| `/role list` | List discovered roles with scope markers and shadowing info. |\n| `/role current` | Show the currently active role's name, extends chain, description, and source path. |\n| `/role reload` | Re-read the **currently active** role's file from disk and re-apply. Useful while you're iterating on a prompt. |\n\n---\n\n## CLI flag and env var\n\n```bash\npi --role architect \"Help me design the auth schema\"\nPI_ROLE=architect pi\n```\n\nResolution order: `--role` > `PI_ROLE` > `defaultRole` setting > built-in `role-assistant`.\n\n---\n\n## Session name and footbar\n\nEach session is named `<role-name>` (and, once the title-generation phase ships, `<role-name> — <intent>`, where `<intent>` is a short summary of your first user message). The role-name prefix updates when you `/role` to a different role.\n\nThe session name is set via Pi's native `pi.setSessionName()` API, so:\n\n- It shows in Pi's session selector and `/resume` listings.\n- [`pi-intercom`](https://github.com/nicobailon/pi-intercom) automatically uses it as the session target — making cross-session messaging work out of the box.\n\nThe role indicator also appears in Pi's footer (via `ctx.ui.setStatus`), composing cleanly with [`pi-powerline-footer`](https://github.com/nicobailon/pi-powerline-footer) if you have it installed. No extra dependency required.\n\n**Title generation model** (planned). The `titleModel` setting is reserved for the future intent-summarization step; it has no effect today. The current release sets the session name to the bare role name and updates the prefix on swap.\n\n---\n\n## pi-intercom integration\n\n[`pi-intercom`](https://github.com/nicobailon/pi-intercom) is an **optional peer dependency**. `pi-roles` works without it; intercom features are no-ops when it's not installed.\n\nWhen it **is** installed, the global `intercomMode` setting controls whether roles get the `intercom` tool added to their active tool set, plus a small system-prompt addendum telling the LLM how and when to use it:\n\n| Mode | Behavior |\n|---|---|\n| `off` | Default. No intercom tools, no prompt mentions. |\n| `receive` | Role can be targeted by other sessions but won't proactively send. |\n| `send` | Role can send to other sessions but doesn't expect inbound coordination. |\n| `both` | Full bidirectional coordination — `intercom` tool active, prompt encourages use. |\n\nPer-role override via the `intercom:` frontmatter field. Common pattern: `architect` and `planner` set `intercom: both`, `orchestrator` sets `intercom: off` (you don't want the orchestrator distracted by chatter while it dispatches).\n\n**Inter-session messaging is always between named sessions on the same machine** — `pi-roles` only opts roles in or out, it doesn't manage the broker, the protocol, or the message store. That's all `pi-intercom`.\n\n---\n\n## pi-mcp-adapter integration\n\nWhen [`pi-mcp-adapter`](https://github.com/nicobailon/pi-mcp-adapter) is installed, you can list MCP tools alongside built-ins in the `tools` field with the `mcp:server-name` syntax:\n\n```yaml\ntools: read, grep, write, mcp:chrome-devtools, mcp:github\n```\n\nThis mirrors `pi-subagents`'s convention exactly, so muscle memory transfers. If `pi-mcp-adapter` isn't installed, the `mcp:*` entries are logged and skipped — the role still loads with its built-in tools.\n\nThe first time you use a new MCP server, its tool metadata is cold-cached; you may need to restart Pi once for direct MCP tools to become available. This is a `pi-mcp-adapter` behavior, not something `pi-roles` controls.\n\n---\n\n## Hot reload\n\n`/role reload` re-reads the **currently active** role's file from disk and re-applies it. This is for iterating on a prompt without restarting your session.\n\n`/role <name>` (without `--reset`) also always re-reads from disk — there's no hidden cache between switches.\n\nFor roles with `extends`, the entire chain is re-resolved on every load.\n\nIf you have Pi's [auto-reload](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/extensions.md#ctxreload) feature wired up via `/reload`, that triggers a full extension reload as well — your role re-applies from scratch.\n\n---\n\n## Settings reference\n\n```json\n// ~/.pi/agent/settings.json (global) or .pi/settings.json (project)\n{\n  \"pi-roles\": {\n    \"roleScope\": \"both\",\n    \"defaultRole\": \"role-assistant\",\n    \"intercomMode\": \"off\",\n    \"titleModel\": \"openai/gpt-4o-mini\",\n    \"warnOnMissingMcp\": true\n  }\n}\n```\n\n| Key | Default | Description |\n|---|---|---|\n| `roleScope` | `\"both\"` | Discovery scope. `\"user\"`, `\"project\"`, or `\"both\"`. |\n| `defaultRole` | `\"role-assistant\"` | Role applied at session start when no `--role` or `PI_ROLE`. |\n| `intercomMode` | `\"off\"` | Default intercom behavior for roles that don't set it explicitly. |\n| `titleModel` | `null` (auto) | Model used for session-intent summarization. Falls back to a small built-in or session's current model. |\n| `warnOnMissingMcp` | `true` | Whether to surface a warning when a role's `mcp:*` entry can't be resolved. |\n\nProject settings beat global settings, per Pi's standard precedence.\n\n---\n\n## What this extension does **not** do\n\n- **Spawn sub-agents.** That's [`pi-subagents`](https://github.com/nicobailon/pi-subagents). The two compose: use `pi-roles` for top-level session roles, `pi-subagents` for delegated workers within a role.\n- **Define any built-in roles other than `role-assistant`.** Roles are user content; the extension stays small.\n- **Manage parallel sessions.** Use multiple terminals or `tmux`. Coordination between parallel sessions is what `pi-intercom` handles, optionally.\n- **Persist which role was active across pi restarts** — except via `--role` / `PI_ROLE` / `defaultRole`. By design.\n- **Restrict which tools a role can request.** If a role lists `bash`, it gets `bash`. Permission boundaries are your call — pair with [`permission-gate.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/examples/extensions/permission-gate.ts) or a similar guard if you need them.\n\n---\n\n## Design choices worth knowing\n\nThese are decided, not configurable, so the extension behaves predictably:\n\n- **Markdown body fully replaces Pi's default system prompt.** No silent merging — most non-coding roles are polluted by the default \"expert coding assistant\" framing, so by design the role body is authoritative. The handler returns `{ systemPrompt: <role body> }` from `before_agent_start` and ignores the upstream chain value. If you want to keep Pi's default content (or compose with another extension), include the relevant text in your role body explicitly.\n- **Role inheritance**: `model`/`thinking` override; `tools` is tri-state (set/empty/absent); markdown body is **prepended**.\n- **Cycle detection in `extends`** is a hard error at load time, not a warning. A circular role is broken; refusing to load it is the only sane behavior.\n- **`/role <name>` always re-reads from disk.** No staleness between switches, ever.\n- **`--reset` is explicit.** The role-assistant prints the exact `--reset` command for you to run manually rather than auto-resetting; resetting is destructive enough to deserve a deliberate keystroke.\n- **Title generation** (planned, not yet implemented). The current release sets the session name to the bare role name; intent-summarization on first user message lands in a follow-up. `--reset` already clears the cached intent so the future implementation drops in cleanly.\n- **Built-in `role-assistant` lives at the lowest discovery priority.** Drop a same-named file in user or project scope to override it.\n- **`/role list` shows shadowed entries** with a `(shadowed)` marker — you can see what *would* load if the higher-priority file didn't exist.\n\n---\n\n## Layout on disk\n\nAfter install, your roles live wherever you like — typical setup:\n\n```\n~/.pi/agent/roles/\n  architect.md\n  planner.md\n  orchestrator.md\n  marketing-strategist.md\n  campaign-manager.md\n\n<repo>/.pi/roles/\n  architect.md          # overrides the user one for this project\n```\n\nThe extension itself ships only `role-assistant.md` (built-in scope) and the runtime code.\n\n---\n\n## Examples\n\nSee [`examples/`](./examples) for two reference role files:\n\n- [`architect.md`](./examples/architect.md) — minimal: just system prompt + model + thinking.\n- [`orchestrator.md`](./examples/orchestrator.md) — fully loaded: every frontmatter field, including `extends`, `intercom`, MCP tools.\n\n---\n\n## License\n\nMIT. See [LICENSE](./LICENSE).\n\n## Credits\n\nInspired by and structurally indebted to [`pi-subagents`](https://github.com/nicobailon/pi-subagents) (frontmatter convention, scope discovery), [`pi-prompt-template-model`](https://github.com/nicobailon/pi-prompt-template-model) (per-trigger model/skill/thinking switching), and the [`preset.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/examples/extensions/preset.ts) example in pi-mono. Thanks to those authors for both the patterns and the working code to learn from.\n","readmeFilename":"README.md","_rev":"1-698bdae12f9ede8a5ef256b9bbb91898"}