@gkzhb/pi-roles 0.2.4-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,70 @@
1
+ # Changelog
2
+
3
+ All notable changes to `pi-roles` will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.0] - 2026-05-05
11
+
12
+ ### Changed
13
+
14
+ - **System prompt full replacement**: Role body now completely replaces Pi's
15
+ default system prompt instead of composing on top of it. Non-coding roles
16
+ (e.g., marketing, research) no longer inherit Pi's default "expert coding
17
+ assistant" framing.
18
+ - **Packaging**: Built output via `tsup`; entry point changed from
19
+ `src/index.ts` to `dist/index.js`; `main`/`exports`/`types` fields added;
20
+ `.npmignore` added.
21
+ - **`/role list` format**: Source scope displayed as `[name]` instead of
22
+ `(name)`; shadowed roles (lower-precedence duplicates) listed separately.
23
+ - **`/role <name>` re-reads from disk**: Every `/role` invocation now
24
+ refreshes role discovery and settings before resolving — edits to role
25
+ files are picked up without an explicit `/role reload`.
26
+ - **`composeSystemPrompt` extracted**: Moved from inline in
27
+ `before_agent_start` to a testable exported function with explicit
28
+ replacement contract.
29
+
30
+ ### Added
31
+
32
+ - **Session naming (Phase 5)**: Session name composed as
33
+ `<role> — <intent>` with intent (~5–10 word summary) generated
34
+ asynchronously from the first user message. Agent loop starts immediately
35
+ while title generation runs out-of-band. Configurable via `titleModel`
36
+ setting.
37
+ - **`titleInFlight` guard**: Prevents concurrent title generation when
38
+ `before_agent_start` fires repeatedly before the first generation resolves.
39
+ - **Shadowed role tracking**: `/role list` shows roles shadowed at
40
+ lower-precedence scopes.
41
+ - **`tsup.config.ts`**: Build configuration for ESM output with type
42
+ declarations.
43
+ - **Tests**: 37 tests for session-naming module (`test/title.test.ts`);
44
+ 6 tests for `composeSystemPrompt` replacement contract
45
+ (`test/index.test.ts`).
46
+
47
+ ## [0.1.0] - TBD
48
+
49
+ ### Added
50
+
51
+ - Initial release.
52
+ - `--role <name>` CLI flag and `PI_ROLE` env var for launching pi as a named role.
53
+ - `/role` slash command with `list`, `current`, `reload`, and `<name>` subcommands.
54
+ - `--reset` flag on `/role <name>` to clear history before applying the new role (equivalent to `/new` + apply).
55
+ - Tab autocompletion for role names.
56
+ - Role frontmatter spec: `name`, `description`, `model`, `thinking`, `tools`, `intercom`, `extends`. Markdown body becomes the system prompt.
57
+ - Discovery from project (`<repo>/.pi/roles/`), user (`~/.pi/agent/roles/`), and built-in scopes, with project-first precedence.
58
+ - `defaultRole` setting, falling back to a built-in `role-assistant` that lists available roles and walks you through building new ones.
59
+ - Role inheritance via `extends`, with chained resolution, cycle detection, and tri-state `tools` semantics (set / explicit-empty / inherit).
60
+ - Markdown body inheritance: parent body prepended to child body.
61
+ - Hot reload via `/role reload` (re-reads currently active role file from disk).
62
+ - Session naming as `<role> — <intent>`, with intent generated asynchronously from the first user message.
63
+ - Role indicator in Pi's footer via `ctx.ui.setStatus`, composing with `pi-powerline-footer`.
64
+ - Optional `pi-intercom` integration: per-role and global `intercomMode` (`off` / `receive` / `send` / `both`), prompt addendum, tool list opt-in. No-op when `pi-intercom` is not installed.
65
+ - Optional `pi-mcp-adapter` integration: `mcp:server-name` entries inside the `tools` field, mirroring `pi-subagents` convention. No-op when `pi-mcp-adapter` is not installed.
66
+ - Two example role files (`examples/architect.md`, `examples/orchestrator.md`).
67
+
68
+ [Unreleased]: https://github.com/lojacobs/pi-roles/compare/v0.2.0...HEAD
69
+ [0.2.0]: https://github.com/lojacobs/pi-roles/compare/v0.1.0...v0.2.0
70
+ [0.1.0]: https://github.com/lojacobs/pi-roles/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Laurent (pi-roles authors)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,367 @@
1
+ # pi-roles
2
+
3
+ > 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.
4
+
5
+ `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.
6
+
7
+ ```bash
8
+ pi --role architect # launch as architect
9
+ PI_ROLE=planner pi # or via env
10
+
11
+ /role list # inside the session
12
+ /role planner # swap role mid-session, keep history
13
+ /role planner --reset # swap role and clear history
14
+ /role current
15
+ /role reload # re-read the active role file from disk
16
+ ```
17
+
18
+ When 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.
19
+
20
+ ---
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ pi install npm:pi-roles
26
+ ```
27
+
28
+ Then restart pi. The extension is auto-discovered; the `--role` flag and `/role` command become available.
29
+
30
+ To try without installing:
31
+
32
+ ```bash
33
+ pi -e git:github.com/lojacobs/pi-roles
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Why this exists
39
+
40
+ When 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.
41
+
42
+ `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.
43
+
44
+ ---
45
+
46
+ ## Role files
47
+
48
+ Roles are markdown files with YAML frontmatter, identical in shape to `pi-subagents` agent files:
49
+
50
+ ```markdown
51
+ ---
52
+ name: architect
53
+ description: Defines the WHAT. Owns architecture and specs. Never codes.
54
+ model: anthropic/claude-opus-4-7
55
+ thinking: high
56
+ tools: read, grep, find, ls, write, edit
57
+ intercom: send # optional, per-role override
58
+ extends: base-reviewer # optional, role inheritance
59
+ ---
60
+
61
+ # Role
62
+
63
+ You are the Architect. Your job is to define WHAT the system should
64
+ do, never HOW to build it...
65
+
66
+ (everything below the frontmatter is the system prompt body)
67
+ ```
68
+
69
+ ### Frontmatter reference
70
+
71
+ | Field | Required | Behavior when omitted |
72
+ |---|---|---|
73
+ | `name` | yes | — must match the filename without `.md` |
74
+ | `description` | yes | — shown in `/role list` and selectors |
75
+ | `model` | no | keeps the session's current model |
76
+ | `thinking` | no | keeps the session's current thinking level (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`) |
77
+ | `tools` | no — see below | inherits from parent (if `extends`) or keeps current active set |
78
+ | `intercom` | no | falls back to the global `intercomMode` setting |
79
+ | `extends` | no | role inherits from another role |
80
+
81
+ #### `tools` — the tri-state
82
+
83
+ Three explicit states with three different meanings:
84
+
85
+ | YAML | Meaning |
86
+ |---|---|
87
+ | `tools: read, bash` | **set** — exactly these tools, nothing else |
88
+ | `tools:` (present, empty) | **disable all tools** — read-only conversation, no actions |
89
+ | field absent | **inherit** — from parent role (`extends`), else keep session default |
90
+
91
+ You can also include MCP tool refs in the same field, mirroring `pi-subagents`:
92
+
93
+ ```yaml
94
+ tools: read, grep, mcp:chrome-devtools, mcp:github
95
+ ```
96
+
97
+ `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.
98
+
99
+ #### `model` — provider/id format
100
+
101
+ Matches Pi's CLI `--model` syntax:
102
+
103
+ ```yaml
104
+ model: anthropic/claude-opus-4-7
105
+ model: openai/gpt-5
106
+ model: deepseek/deepseek-v4-pro
107
+ ```
108
+
109
+ If the model isn't available (no API key, unknown provider), the role load surfaces a warning and the session keeps its current model.
110
+
111
+ #### `intercom` — per-role override
112
+
113
+ Values: `off`, `receive`, `send`, `both`. Defaults to the global `intercomMode` setting (which itself defaults to `off`). See [pi-intercom integration](#pi-intercom-integration) below.
114
+
115
+ #### `extends` — role inheritance
116
+
117
+ ```yaml
118
+ extends: architect
119
+ ```
120
+
121
+ A 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.
122
+
123
+ **Merge rules:**
124
+
125
+ - `model`, `thinking`, `description`, `intercom`: child wins if set, else parent value.
126
+ - `tools`: see the tri-state above. **Set overrides; empty disables; absent inherits.**
127
+ - Markdown body: parent's body is **prepended** to child's body with a separator. Useful for "stricter variant" patterns (`architect-strict extends architect`).
128
+ - `name`: never inherited — always the child's own filename.
129
+
130
+ ---
131
+
132
+ ## Discovery
133
+
134
+ Roles are looked up in this order, **first match wins** for any given name:
135
+
136
+ | Scope | Path | Marker in `/role list` |
137
+ |---|---|---|
138
+ | project | `<repo>/.pi/roles/<name>.md` (or any ancestor) | `[project]` |
139
+ | user | `~/.pi/agent/roles/<name>.md` | `[user]` |
140
+ | built-in | bundled with the package | `[built-in]` |
141
+
142
+ When 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.
143
+
144
+ The default `roleScope` is `both` (project + user + built-in). Override via settings:
145
+
146
+ ```json
147
+ // ~/.pi/agent/settings.json
148
+ {
149
+ "pi-roles": {
150
+ "roleScope": "both", // "user" | "project" | "both"
151
+ "defaultRole": "architect", // optional; falls back to role-assistant
152
+ "preserveRoleOnNewSession": false, // optional; keep the active role for /new
153
+ "intercomMode": "off", // "off" | "receive" | "send" | "both"
154
+ "titleModel": "openai/gpt-4o-mini"
155
+ }
156
+ }
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Built-in `role-assistant`
162
+
163
+ `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`.
164
+
165
+ The role-assistant:
166
+
167
+ 1. Lists the roles available on your machine (project + user + built-in) on its first turn.
168
+ 2. Shows the exact command to switch to one (e.g. `/role architect`).
169
+ 3. 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`).
170
+
171
+ You can override the built-in by dropping a `role-assistant.md` into your project or user roles directory — the same priority rules apply.
172
+
173
+ You can also set any other role as your default:
174
+
175
+ ```json
176
+ { "pi-roles": { "defaultRole": "architect" } }
177
+ ```
178
+
179
+ If `defaultRole` points to a missing role, the built-in `role-assistant` is used and a warning is shown.
180
+
181
+ ### Retain the role in new conversations
182
+
183
+ By default, a normal new conversation resolves its role again from `--role`, `PI_ROLE`, `defaultRole`, and finally `role-assistant`. To keep the role selected in the current Pi process when creating a new conversation, enable:
184
+
185
+ ```json
186
+ { "pi-roles": { "preserveRoleOnNewSession": true } }
187
+ ```
188
+
189
+ This applies only to ordinary new conversations. `/role <name> --reset` still uses its explicitly requested role; reload and resume restore their session role as before. The setting does not persist a role across a Pi restart—on startup, the normal initial-role resolution still applies.
190
+
191
+ ---
192
+
193
+ ## Slash command
194
+
195
+ `/role <subcommand>` — Tab-completes role names against the current scope.
196
+
197
+ | Form | Behavior |
198
+ |---|---|
199
+ | `/role <name>` | Switch to `<name>`. **Preserves history.** Re-reads the file from disk (no caching). |
200
+ | `/role <name> --reset` | Switch to `<name>` **and** clear history (equivalent to `/new` + apply role). |
201
+ | `/role list` | List discovered roles with scope markers and shadowing info. |
202
+ | `/role current` | Show the currently active role's name, extends chain, description, and source path. |
203
+ | `/role reload` | Re-read the **currently active** role's file from disk and re-apply. Useful while you're iterating on a prompt. |
204
+
205
+ ---
206
+
207
+ ## CLI flag and env var
208
+
209
+ ```bash
210
+ pi --role architect "Help me design the auth schema"
211
+ PI_ROLE=architect pi
212
+ ```
213
+
214
+ Resolution order: `--role` > `PI_ROLE` > `defaultRole` setting > built-in `role-assistant`.
215
+
216
+ ---
217
+
218
+ ## Session name and footbar
219
+
220
+ Each 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.
221
+
222
+ The session name is set via Pi's native `pi.setSessionName()` API, so:
223
+
224
+ - It shows in Pi's session selector and `/resume` listings.
225
+ - [`pi-intercom`](https://github.com/nicobailon/pi-intercom) automatically uses it as the session target — making cross-session messaging work out of the box.
226
+
227
+ The 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.
228
+
229
+ **Title generation model.** `titleModel` selects the model used to summarize the first user message into the session intent. The extension resolves its credentials through Pi's model registry, so provider API keys, headers, and environment-variable references configured in Pi's `models.json` are forwarded to the title request. The setting falls back to the session's current model when omitted or unavailable.
230
+
231
+ ---
232
+
233
+ ## pi-intercom integration
234
+
235
+ [`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.
236
+
237
+ When 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:
238
+
239
+ | Mode | Behavior |
240
+ |---|---|
241
+ | `off` | Default. No intercom tools, no prompt mentions. |
242
+ | `receive` | Role can be targeted by other sessions but won't proactively send. |
243
+ | `send` | Role can send to other sessions but doesn't expect inbound coordination. |
244
+ | `both` | Full bidirectional coordination — `intercom` tool active, prompt encourages use. |
245
+
246
+ Per-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).
247
+
248
+ **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`.
249
+
250
+ ---
251
+
252
+ ## pi-mcp-adapter integration
253
+
254
+ When [`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:
255
+
256
+ ```yaml
257
+ tools: read, grep, write, mcp:chrome-devtools, mcp:github
258
+ ```
259
+
260
+ This 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.
261
+
262
+ The 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.
263
+
264
+ ---
265
+
266
+ ## Hot reload
267
+
268
+ `/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.
269
+
270
+ `/role <name>` (without `--reset`) also always re-reads from disk — there's no hidden cache between switches.
271
+
272
+ For roles with `extends`, the entire chain is re-resolved on every load.
273
+
274
+ If 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.
275
+
276
+ ---
277
+
278
+ ## Settings reference
279
+
280
+ ```json
281
+ // ~/.pi/agent/settings.json (global) or .pi/settings.json (project)
282
+ {
283
+ "pi-roles": {
284
+ "roleScope": "both",
285
+ "defaultRole": "role-assistant",
286
+ "preserveRoleOnNewSession": false,
287
+ "intercomMode": "off",
288
+ "titleModel": "openai/gpt-4o-mini",
289
+ "warnOnMissingMcp": true
290
+ }
291
+ }
292
+ ```
293
+
294
+ | Key | Default | Description |
295
+ |---|---|---|
296
+ | `roleScope` | `"both"` | Discovery scope. `"user"`, `"project"`, or `"both"`. |
297
+ | `defaultRole` | `"role-assistant"` | Role applied at session start when no `--role` or `PI_ROLE`. |
298
+ | `preserveRoleOnNewSession` | `false` | Keep the current process's active role when creating a normal new conversation. Does not apply across restarts or to explicit `/role <name> --reset`. |
299
+ | `intercomMode` | `"off"` | Default intercom behavior for roles that don't set it explicitly. |
300
+ | `titleModel` | `null` (auto) | Model used for session-intent summarization. Its API key and request headers are resolved from Pi's model registry, including `models.json` environment-variable configuration. Falls back to the session's current model. |
301
+ | `warnOnMissingMcp` | `true` | Whether to surface a warning when a role's `mcp:*` entry can't be resolved. |
302
+
303
+ Project settings beat global settings, per Pi's standard precedence.
304
+
305
+ ---
306
+
307
+ ## What this extension does **not** do
308
+
309
+ - **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.
310
+ - **Define any built-in roles other than `role-assistant`.** Roles are user content; the extension stays small.
311
+ - **Manage parallel sessions.** Use multiple terminals or `tmux`. Coordination between parallel sessions is what `pi-intercom` handles, optionally.
312
+ - **Persist which role was active across pi restarts** — except via `--role` / `PI_ROLE` / `defaultRole`. By design.
313
+ - **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.
314
+
315
+ ---
316
+
317
+ ## Design choices worth knowing
318
+
319
+ These are decided, not configurable, so the extension behaves predictably:
320
+
321
+ - **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.
322
+ - **Role inheritance**: `model`/`thinking` override; `tools` is tri-state (set/empty/absent); markdown body is **prepended**.
323
+ - **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.
324
+ - **`/role <name>` always re-reads from disk.** No staleness between switches, ever.
325
+ - **`--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.
326
+ - **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.
327
+ - **Built-in `role-assistant` lives at the lowest discovery priority.** Drop a same-named file in user or project scope to override it.
328
+ - **`/role list` shows shadowed entries** with a `(shadowed)` marker — you can see what *would* load if the higher-priority file didn't exist.
329
+
330
+ ---
331
+
332
+ ## Layout on disk
333
+
334
+ After install, your roles live wherever you like — typical setup:
335
+
336
+ ```
337
+ ~/.pi/agent/roles/
338
+ architect.md
339
+ planner.md
340
+ orchestrator.md
341
+ marketing-strategist.md
342
+ campaign-manager.md
343
+
344
+ <repo>/.pi/roles/
345
+ architect.md # overrides the user one for this project
346
+ ```
347
+
348
+ The extension itself ships only `role-assistant.md` (built-in scope) and the runtime code.
349
+
350
+ ---
351
+
352
+ ## Examples
353
+
354
+ See [`examples/`](./examples) for two reference role files:
355
+
356
+ - [`architect.md`](./examples/architect.md) — minimal: just system prompt + model + thinking.
357
+ - [`orchestrator.md`](./examples/orchestrator.md) — fully loaded: every frontmatter field, including `extends`, `intercom`, MCP tools.
358
+
359
+ ---
360
+
361
+ ## License
362
+
363
+ MIT. See [LICENSE](./LICENSE).
364
+
365
+ ## Credits
366
+
367
+ Inspired 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.