The extension resolves project config paths from process.cwd() instead of the session's
ctx.cwd. When a session's workspace differs from the process working directory,
.pi/agents/ and .pi/subagents.json are read from the wrong tree — silently.
Every Agent call then falls back to the built-in general-purpose. Because that agent uses
prompt_mode: append, subagents inherit the full parent prompt and the complete tool set, so
tools:, disallowed_tools:, extensions: false and isolated: true are all ignored —
agents authored as read-only get edit/write. The only hint is
Unknown agent type "<name>" — using general-purpose, which reads like a typo, not a path bug.
Call sites (master): src/index.ts 283 (loadCustomAgents), 872
(agent-tool-description.md), 1572-1573 (agent dirs), 750 (applyAndEmitLoaded called
without cwd); src/settings.ts 251, 260, 310, 328 (cwd: string = process.cwd() defaults).
saveSettings shares the default, so settings written from /agents → Settings also land
outside the project.
When the two differ. Not in normal CLI use — running pi inside the project makes
process.cwd() === ctx.cwd, which is presumably why this went unnoticed. The CLI actively
keeps it that way: resuming a session from another directory prompts
Session found in different project — fork into current directory?, and the fork rewrites the
session cwd to the current one. So the divergence is reachable through the SDK
(docs/sdk.md, "embed pi in other applications"): a host process that creates sessions whose
workspace is not the directory the process was started in. That is what I hit.
Repro — pi 0.83.0, extension 0.14.3, node 24.18.0, Linux.
- Project at
/home/me/project containing .pi/agents/my-agent.md and .pi/subagents.json
- Embed pi via the SDK and open a session with that project as its workspace, from a process
whose own cwd is elsewhere (e.g. $HOME)
- Confirm the workspace is correct —
bash pwd, git branch and file listing all report the project
- Call
Agent({ subagent_type: "my-agent", ... })
Actual: Unknown agent type "my-agent" — using general-purpose; .pi/subagents.json is
ignored as well (maxConcurrent, outputTranscript, toolDescriptionMode fall back to defaults).
Expected: the agent from .pi/agents/ is used and project settings apply.
Fix direction: ctx.cwd is already used throughout the same file (resolveStorePath,
createOutputFilePath, readEnabledModels), and the SDK documents this pattern for project
config — docs/extensions.md:958-962 shows
pi.on("session_start", (_event, ctx) => join(ctx.cwd, CONFIG_DIR_NAME, "my-extension.json")).
reloadCustomAgents() has 15 call sites and all but the init one at index.ts:288 have ctx
in scope, so threading cwd through is mostly mechanical.
I fixed the same bug in two extensions of my own, and after the change they work correctly in
the very same host process that still breaks this one — so a one-sided fix here is sufficient.
Happy to open a PR if you want it.
The extension resolves project config paths from
process.cwd()instead of the session'sctx.cwd. When a session's workspace differs from the process working directory,.pi/agents/and.pi/subagents.jsonare read from the wrong tree — silently.Every
Agentcall then falls back to the built-ingeneral-purpose. Because that agent usesprompt_mode: append, subagents inherit the full parent prompt and the complete tool set, sotools:,disallowed_tools:,extensions: falseandisolated: trueare all ignored —agents authored as read-only get
edit/write. The only hint isUnknown agent type "<name>" — using general-purpose, which reads like a typo, not a path bug.Call sites (
master):src/index.ts283 (loadCustomAgents), 872(
agent-tool-description.md), 1572-1573 (agent dirs), 750 (applyAndEmitLoadedcalledwithout
cwd);src/settings.ts251, 260, 310, 328 (cwd: string = process.cwd()defaults).saveSettingsshares the default, so settings written from/agents → Settingsalso landoutside the project.
When the two differ. Not in normal CLI use — running
piinside the project makesprocess.cwd() === ctx.cwd, which is presumably why this went unnoticed. The CLI activelykeeps it that way: resuming a session from another directory prompts
Session found in different project — fork into current directory?, and the fork rewrites thesession cwd to the current one. So the divergence is reachable through the SDK
(
docs/sdk.md, "embed pi in other applications"): a host process that creates sessions whoseworkspace is not the directory the process was started in. That is what I hit.
Repro — pi 0.83.0, extension 0.14.3, node 24.18.0, Linux.
/home/me/projectcontaining.pi/agents/my-agent.mdand.pi/subagents.jsonwhose own cwd is elsewhere (e.g.
$HOME)bash pwd, git branch and file listing all report the projectAgent({ subagent_type: "my-agent", ... })Actual:
Unknown agent type "my-agent" — using general-purpose;.pi/subagents.jsonisignored as well (
maxConcurrent,outputTranscript,toolDescriptionModefall back to defaults).Expected: the agent from
.pi/agents/is used and project settings apply.Fix direction:
ctx.cwdis already used throughout the same file (resolveStorePath,createOutputFilePath,readEnabledModels), and the SDK documents this pattern for projectconfig —
docs/extensions.md:958-962showspi.on("session_start", (_event, ctx) => join(ctx.cwd, CONFIG_DIR_NAME, "my-extension.json")).reloadCustomAgents()has 15 call sites and all but the init one atindex.ts:288havectxin scope, so threading
cwdthrough is mostly mechanical.I fixed the same bug in two extensions of my own, and after the change they work correctly in
the very same host process that still breaks this one — so a one-sided fix here is sufficient.
Happy to open a PR if you want it.