pi-subagents-j0k3r 1.0.1 → 1.1.0

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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0 - 2026-06-27
4
+
5
+ ### Added
6
+ - Added support for loading markdown-defined subagents from both `agents` and `subagents` directories globally and project-locally.
7
+ - Added startup warnings when duplicate names exist in `agents` and `subagents` at the same scope, while preserving `subagents` as the winning source.
8
+ - Enabled project Skill Registry configuration and ignored generated registry cache outputs.
9
+
10
+ ### Fixed
11
+ - Made `model_profiles` global-only so project-local `.pi/subagents.json` cannot override per-agent model/effort routing.
12
+
13
+ ### Documentation
14
+ - Updated README and Subagents configuration skill guidance for `agents`/`subagents` source precedence and global-only model profiles.
15
+
3
16
  ## 1.0.1 - 2026-06-27
4
17
 
5
18
  ### Fixed
package/README.md CHANGED
@@ -67,10 +67,12 @@ Subagents are markdown files with optional YAML-like frontmatter.
67
67
 
68
68
  Load order:
69
69
 
70
- 1. Global user subagents from `$PI_CODING_AGENT_DIR/subagents/*.md`.
71
- 2. Project subagents from `.pi/subagents/*.md`.
70
+ 1. Global user agents from `$PI_CODING_AGENT_DIR/agents/*.md`.
71
+ 2. Global user subagents from `$PI_CODING_AGENT_DIR/subagents/*.md`.
72
+ 3. Project agents from `.pi/agents/*.md`.
73
+ 4. Project subagents from `.pi/subagents/*.md`.
72
74
 
73
- Project definitions override global definitions with the same normalized name.
75
+ Project definitions override global definitions with the same normalized name. Within the same scope, `subagents` definitions override `agents` definitions with the same normalized name and Pi shows a startup warning so the duplicate can be cleaned up.
74
76
 
75
77
  Default global agent directory:
76
78
 
@@ -127,7 +129,7 @@ Config files:
127
129
  .pi/subagents.json # project
128
130
  ```
129
131
 
130
- Config resolves as a cascade: project `.pi/subagents.json` overrides global `~/.pi/agent/subagents.json`; missing project fields fall back to global config; fields missing from both fall back to built-in defaults. Model profiles are merged by normalized lowercase agent name, with project profile fields overriding global profile fields.
132
+ Config resolves as a cascade: project `.pi/subagents.json` overrides global `~/.pi/agent/subagents.json`; missing project fields fall back to global config; fields missing from both fall back to built-in defaults. `model_profiles` are the explicit exception: per-agent model/effort routing is read only from the global `~/.pi/agent/subagents.json` or `$PI_CODING_AGENT_DIR/subagents.json`, and project-local `model_profiles` are ignored.
131
133
 
132
134
  Example:
133
135
 
@@ -168,7 +170,7 @@ Example:
168
170
  |---|---:|---|
169
171
  | `default_model` | current orchestrator model | Fallback model for all subagents. Format: `provider/model-id`. |
170
172
  | `default_effort` | current orchestrator effort | Fallback thinking effort. Also accepts `default_thinking_level` or `thinkingLevel`. |
171
- | `model_profiles` | `{}` | Per-agent model/effort overrides. |
173
+ | `model_profiles` | `{}` | Global-only per-agent model/effort overrides. Project-local `.pi/subagents.json` `model_profiles` are ignored. |
172
174
  | `timeout_ms` | `600000` | Total timeout per subagent task. |
173
175
  | `stall_timeout_ms` | `120000` | Inactivity timeout for a subagent session. |
174
176
  | `max_concurrency` | `5` | Max concurrent subagent tasks per cwd/config pair. |
@@ -392,7 +394,7 @@ This package bundles:
392
394
  - `index.ts` and `src/**` — the Pi extension runtime.
393
395
  - `skills/subagents-configuration/SKILL.md` — configuration guidance for agents that need to create or edit subagent definitions.
394
396
 
395
- Subagent definitions are intentionally user/project configuration, not hard-coded package behavior. Add them globally in `$PI_CODING_AGENT_DIR/subagents/*.md` or project-locally in `.pi/subagents/*.md`.
397
+ Subagent definitions are intentionally user/project configuration, not hard-coded package behavior. Add them globally in `$PI_CODING_AGENT_DIR/agents/*.md` or `$PI_CODING_AGENT_DIR/subagents/*.md`, or project-locally in `.pi/agents/*.md` or `.pi/subagents/*.md`.
396
398
 
397
399
  ## Development
398
400
 
package/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { SubagentManager } from './src/manager.js';
2
- import { readSubagentsConfig } from './src/config.js';
2
+ import { readSubagentsConfig, subagentSourceWarnings } from './src/config.js';
3
3
  import { registerSubagentTools, triggerClaudeBackgroundHandoff } from './src/tools.js';
4
4
  import { runSubagentModelsCommand } from './src/model-profiles-ui.js';
5
5
  import { SubagentsHistoryPanel } from './src/ui.js';
@@ -412,6 +412,8 @@ export default function subagentsExtension(pi: any): void {
412
412
 
413
413
  pi.on?.('session_start', (_event: unknown, ctx: any) => {
414
414
  clearClaudeBackgroundWidget();
415
+ const cwd = ctx?.cwd ?? process.cwd();
416
+ for (const warning of subagentSourceWarnings(cwd)) ctx?.ui?.notify?.(warning, 'warning');
415
417
  if (typeof ctx?.ui?.setWidget !== 'function') return;
416
418
  widgetCtx = ctx;
417
419
  if (!installClaudeBackgroundWidget(ctx)) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-subagents-j0k3r",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Installable Pi package that adds markdown-defined subagents, delegated task tools, history, and model profiles.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -19,10 +19,13 @@ Use this block as the machine-readable source for `.pi/skill-registry.json` gene
19
19
  "domains": ["subagents-configuration", "subagent-config", "model-profile-config", "tool-allowlist-config", "subagent-history-config", "subagent-shortcut-config"],
20
20
  "triggers": {
21
21
  "paths": [
22
+ ".pi/agents/**/*.md",
22
23
  ".pi/subagents/**/*.md",
23
24
  ".pi/subagents.json",
25
+ "agents/**/*.md",
24
26
  "subagents/**/*.md",
25
27
  "subagents.json",
28
+ "~/.pi/agent/agents/**/*.md",
26
29
  "~/.pi/agent/subagents/**/*.md",
27
30
  "~/.pi/agent/subagents.json"
28
31
  ],
@@ -88,11 +91,11 @@ Do not load this skill for ordinary subagent delegation/use (`subagent_run`, tas
88
91
  - Prefer narrow tool allowlists per subagent. Do not grant write/bash tools unless the subagent purpose requires them.
89
92
  - For SDD/PRD phase agents, prefer deterministic active-flow memory tools only: `memory_search`, `memory_get`, `memory_add`, and `memory_update`; avoid `memory_context` and `memory_recall` in subagent allowlists unless there is a specific reviewed need.
90
93
  - For SDD phase agents, memory write tools may be allowed only for active SDD flow memory/artifacts according to `sdd-workflow`.
91
- - Project subagents live in `.pi/subagents/*.md`; global user subagents live in `$PI_CODING_AGENT_DIR/subagents/*.md` or `~/.pi/agent/subagents/*.md`.
92
- - Project definitions override global definitions with the same normalized name.
93
- - Subagents config resolves as a cascade: project `.pi/subagents.json` overrides global `$PI_CODING_AGENT_DIR/subagents.json` or `~/.pi/agent/subagents.json`; missing project fields fall back to global config; fields missing from both fall back to built-in defaults. Communicate this precedence to users when explaining config behavior.
94
- - `model_profiles` are deep-merged by agent name with project-local profile fields taking precedence over global profile fields.
95
- - Prefer configuring subagent `model` and `effort` in global or project `subagents.json` under `model_profiles`, not in the subagent markdown frontmatter. Markdown definitions should usually contain identity, description, tool allowlist, and behavioral instructions only.
94
+ - Project subagent definitions live in `.pi/agents/*.md` and `.pi/subagents/*.md`; global user definitions live in `$PI_CODING_AGENT_DIR/agents/*.md`, `$PI_CODING_AGENT_DIR/subagents/*.md`, `~/.pi/agent/agents/*.md`, or `~/.pi/agent/subagents/*.md`.
95
+ - Project definitions override global definitions with the same normalized name. Within the same scope, definitions in `subagents` override definitions in `agents` with the same normalized name, and Pi should warn at session startup so users can clean up the duplicate.
96
+ - Subagents config resolves as a cascade: project `.pi/subagents.json` overrides global `$PI_CODING_AGENT_DIR/subagents.json` or `~/.pi/agent/subagents.json`; missing project fields fall back to global config; fields missing from both fall back to built-in defaults. Communicate this precedence to users when explaining config behavior, with the explicit exception that `model_profiles` are global-only.
97
+ - `model_profiles` are read only from global `$PI_CODING_AGENT_DIR/subagents.json` or `~/.pi/agent/subagents.json`; project-local `.pi/subagents.json` must not set or override subagent model/effort routing.
98
+ - Prefer configuring subagent `model` and `effort` in global `subagents.json` under `model_profiles`, not in project-local config or in the subagent markdown frontmatter. Markdown definitions should usually contain identity, description, tool allowlist, and behavioral instructions only.
96
99
  - Nested subagent sessions should use `session_resources: "lean"` by default so the subagent markdown body becomes the nested session system prompt, the delegated user prompt contains only orchestrator context/task, and workflow skills, prompt templates, themes, context files, and startup context injections are not auto-loaded.
97
100
  - In lean mode, extensions are loaded for allowlisted tools and tool-safety hooks only; prompt/context lifecycle hooks such as `before_agent_start` and `context` must not inject hidden messages into subagent turns.
98
101
  - Subagent task history is stored globally under data storage, but rows remain project-scoped by `cwd`; history stores delegated prompt and subagent system prompt separately.
@@ -151,7 +154,7 @@ tools:
151
154
  Instructions...
152
155
  ```
153
156
 
154
- Configure routing separately in `subagents.json` when needed. If no profile/default is configured, the subagent inherits the current orchestrator model and thinking effort.
157
+ Configure model/effort routing separately in the global `subagents.json` when needed. If no global profile/default is configured, the subagent inherits the current orchestrator model and thinking effort.
155
158
 
156
159
  ```json
157
160
  {
@@ -166,9 +169,9 @@ Configure routing separately in `subagents.json` when needed. If no profile/defa
166
169
 
167
170
  Model/effort resolution order:
168
171
 
169
- 1. `model_profiles[agentName]` in `subagents.json`.
172
+ 1. Global `model_profiles[agentName]` in `$PI_CODING_AGENT_DIR/subagents.json` or `~/.pi/agent/subagents.json`.
170
173
  2. Markdown frontmatter `model` / `effort` only for explicit per-file overrides.
171
- 3. `default_model` / `default_effort` in `subagents.json`.
174
+ 3. `default_model` / `default_effort` from effective `subagents.json` config.
172
175
  4. Current orchestrator model / effort.
173
176
 
174
177
  ## Decision Gates
@@ -176,16 +179,16 @@ Model/effort resolution order:
176
179
  - If the subagent will modify files, run bash, or write memory, ask whether a full SDD workflow or stricter review is required.
177
180
  - If the subagent needs human input, require a structured `interaction_required` request with enough prompt, payload, and expected-response data for the parent to answer.
178
181
  - If a project wants many subagents or broad tools, recommend starting with read-only discovery agents and expanding deliberately.
179
- - If model profiles are global, confirm the user wants global behavior rather than project-only config.
182
+ - If the user asks for project-local model profiles, explain that `model_profiles` are global-only and ask whether they want to update the global config instead.
180
183
 
181
184
  ## Execution Steps
182
185
 
183
186
  1. Identify target scope: npm package install/update, global subagent, project subagent, global config, or project config, and explain the cascade when relevant: project-local config first, then global config for missing fields, then built-in defaults.
184
187
  2. For package setup, inspect settings before editing; use `pi install npm:pi-subagents-j0k3r` when possible, or edit `~/.pi/agent/settings.json` only when the CLI is unavailable/broken. Prefer unpinned `npm:pi-subagents-j0k3r` unless the user asks for a fixed version.
185
- 3. Read existing subagent markdown/config before editing.
186
- 4. For new subagents, choose lowercase kebab-case names and clear trigger-focused descriptions.
188
+ 3. Read existing subagent markdown/config before editing, checking both `agents` and `subagents` directories for the requested scope.
189
+ 4. For new subagents, choose lowercase kebab-case names and clear trigger-focused descriptions. Prefer `subagents` for new definitions unless the user explicitly needs compatibility with an `agents` harness.
187
190
  5. Set minimal tool allowlists; remove any `subagent_*` entries.
188
- 6. Configure `model_profiles`, `default_model`, and `default_effort` in `subagents.json` only when the user wants explicit routing; do not put model routing in subagent markdown unless the user explicitly asks for per-file overrides. Explain that unconfigured fields inherit from the orchestrator.
191
+ 6. Configure `model_profiles` only in global `subagents.json` when the user wants explicit per-agent routing; project-local `model_profiles` are ignored. Configure `default_model` and `default_effort` in effective `subagents.json` only when the user wants defaults. Do not put model routing in subagent markdown unless the user explicitly asks for per-file overrides. Explain that unconfigured fields inherit from the orchestrator.
189
192
  7. Configure `debug: true` only for temporary diagnostics; keep `debug: false` by default and remember logs are written under the executing project's `.pi` directory.
190
193
  8. Validate JSON syntax for settings/subagents config and frontmatter/body structure for markdown agents.
191
194
  9. When configuring OpenCode-mode history opening, prefer `history_panel_shortcut` with `ctrl+<letter>` or `ctrl+,` values and document any built-in shortcut conflicts.
@@ -200,7 +203,7 @@ Model/effort resolution order:
200
203
  Return:
201
204
 
202
205
  - Skill applied: `subagents-configuration`.
203
- - Scope/path configured or reviewed.
206
+ - Scope/path configured or reviewed, including whether definitions came from `agents` or `subagents`.
204
207
  - Package settings and subagents/config fields added, changed, or preserved.
205
208
  - Tool allowlist, system-prompt isolation, Context7 scope, memory-tool scope, debug logging, model/effort decisions, and inheritance behavior.
206
209
  - Runtime behavior explained when relevant: task vs background, automatic notifications, `/subagents`, `ctrl+o`, and `subagent_result`.
package/src/config.ts CHANGED
@@ -163,16 +163,6 @@ function parseModelProfiles(value: unknown): SubagentModelProfiles {
163
163
  return profiles;
164
164
  }
165
165
 
166
- function mergeModelProfiles(globalRaw: unknown, projectRaw: unknown): SubagentModelProfiles {
167
- const globalProfiles = parseModelProfiles(globalRaw);
168
- const projectProfiles = parseModelProfiles(projectRaw);
169
- const merged: SubagentModelProfiles = { ...globalProfiles };
170
- for (const [name, projectProfile] of Object.entries(projectProfiles)) {
171
- merged[name] = { ...(merged[name] ?? {}), ...projectProfile };
172
- }
173
- return merged;
174
- }
175
-
176
166
  function serializeModelRef(model: ModelRef): string {
177
167
  return `${model.provider}/${model.id}`;
178
168
  }
@@ -191,7 +181,7 @@ export function readSubagentsConfig(cwd: string): SubagentsConfig {
191
181
  return {
192
182
  default_model: parseModel(raw.default_model),
193
183
  default_effort: parseEffort(raw.default_effort ?? raw.default_thinking_level ?? raw.thinkingLevel),
194
- model_profiles: mergeModelProfiles(globalRaw.model_profiles, projectRaw.model_profiles),
184
+ model_profiles: parseModelProfiles(globalRaw.model_profiles),
195
185
  timeout_ms: positiveInteger(raw.timeout_ms, DEFAULT_TIMEOUT_MS),
196
186
  stall_timeout_ms: positiveInteger(raw.stall_timeout_ms, DEFAULT_STALL_TIMEOUT_MS),
197
187
  max_concurrency: positiveInteger(raw.max_concurrency, DEFAULT_MAX_CONCURRENCY),
@@ -250,10 +240,37 @@ function loadSubagentsFromDir(dir: string): SubagentDefinition[] {
250
240
  });
251
241
  }
252
242
 
243
+ function agentsDirSources(cwd: string): Array<{ scope: 'global' | 'project'; kind: 'agents' | 'subagents'; dir: string }> {
244
+ const globalAgentDir = agentDir();
245
+ return [
246
+ { scope: 'global', kind: 'agents', dir: path.join(globalAgentDir, 'agents') },
247
+ { scope: 'global', kind: 'subagents', dir: path.join(globalAgentDir, 'subagents') },
248
+ { scope: 'project', kind: 'agents', dir: path.join(cwd, '.pi', 'agents') },
249
+ { scope: 'project', kind: 'subagents', dir: path.join(cwd, '.pi', 'subagents') },
250
+ ];
251
+ }
252
+
253
+ export function subagentSourceWarnings(cwd: string): string[] {
254
+ const warnings: string[] = [];
255
+ for (const scope of ['global', 'project'] as const) {
256
+ const sources = agentsDirSources(cwd).filter((source) => source.scope === scope);
257
+ const agents = loadSubagentsFromDir(sources.find((source) => source.kind === 'agents')!.dir);
258
+ const subagents = loadSubagentsFromDir(sources.find((source) => source.kind === 'subagents')!.dir);
259
+ const subagentNames = new Map(subagents.map((definition) => [definition.name, definition]));
260
+ for (const agent of agents) {
261
+ const subagent = subagentNames.get(agent.name);
262
+ if (!subagent) continue;
263
+ warnings.push(`Duplicate subagent name "${agent.name}" found in ${scope} agents and subagents directories; using subagents definition (${subagent.filePath}).`);
264
+ }
265
+ }
266
+ return warnings;
267
+ }
268
+
253
269
  export function loadSubagents(cwd: string): SubagentDefinition[] {
254
270
  const byName = new Map<string, SubagentDefinition>();
255
- for (const agent of loadSubagentsFromDir(path.join(agentDir(), 'subagents'))) byName.set(agent.name, agent);
256
- for (const agent of loadSubagentsFromDir(path.join(cwd, '.pi', 'subagents'))) byName.set(agent.name, agent);
271
+ for (const source of agentsDirSources(cwd)) {
272
+ for (const agent of loadSubagentsFromDir(source.dir)) byName.set(agent.name, agent);
273
+ }
257
274
  return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
258
275
  }
259
276
 
package/src/tools.ts CHANGED
@@ -299,7 +299,7 @@ export function registerSubagentTools(pi: any, manager: SubagentManager): void {
299
299
  name: 'subagent_list_agents',
300
300
  label: 'Subagent List Agents',
301
301
  description: 'List available markdown-defined subagents for delegation.',
302
- promptSnippet: 'List available subagents loaded from .pi/subagents/*.md.',
302
+ promptSnippet: 'List available subagents loaded from global/project agents and subagents markdown directories.',
303
303
  parameters: Type.Object({}),
304
304
  async execute(_id: string, _params: any, _signal: any, _onUpdate: any, ctx: any) {
305
305
  try { const agents = manager.listAgents(ctx?.cwd ?? process.cwd()); return ok(`Found ${agents.length} subagent(s).`, { agents }); } catch (e) { return fail(e); }