[Bug]: Pi adapter hardcodes legacy Pi paths — `~/.pi/settings.json` and `~/.pi/extensions/context-mode/` do not exist

Author: cshunkeCreated Sep 16, 2026Updated Sep 16, 2026

Environment

  • context-mode 1.0.169 (installed via pi install npm:context-mode)
  • Pi Coding Agent 0.85.1, macOS
  • ctx_doctor (MCP tool)

What I saw

ctx_doctor reports:

[OK] Hook support: Pi hooks are wired via the context-mode Pi extension (~/.pi/extensions/context-mode/), not via JSON-stdio.

That path does not exist on my machine, and ~/.pi/extensions/ is not one of Pi's extension-discovery locations:

$ ls ~/.pi/
agent		context-mode
$ ls ~/.pi/extensions/
ls: /Users/shun/.pi/extensions/: No such file or directory

Root cause

src/adapters/pi/index.ts encodes a Pi directory layout that Pi no longer uses (and that the README does not describe). Three separate places, plus the header comment:

Location Assumes Actual
getSettingsPath() (L122) ~/.pi/settings.json ~/.pi/agent/settings.json
checkPluginRegistration() (L163–169) ~/.pi/extensions/context-mode/package.json npm package install; no such file
getInstalledVersion() (L200–202) same file same
validateHooks() (L157) prints that same path to the user
header comment (L14–16) documents ~/.pi/settings.json ~/.pi/agent/settings.json

Evidence

  1. Your own README contradicts the adapter. The Pi Coding Agent section says to run pi install npm:context-mode, or add to ~/.pi/agent/settings.json (or .pi/settings.json):

    json
    { "packages": ["npm:context-mode"] }

    It never mentions ~/.pi/extensions/. The README path is correct; the adapter path is not.

  2. Pi's documented discovery locations are ~/.pi/agent/extensions/*/index.ts (global) and .pi/extensions/*/index.ts (project-local). ~/.pi/extensions/ appears in neither, so an extension placed there would not load.

  3. context-mode upgrade cannot fix this. The published package does not ship a .pi/ directory — .pi/extensions/context-mode/package.json exists only in the git repo (referenced by the version script's git add), and files in package.json excludes .pi. So if checkPluginRegistration() ever runs it returns fail with fix: "Run: context-mode upgrade", an instruction that can never produce the file it is looking for.

  4. configureAllHooks() returning [] means the doctor never calls it, so checkPluginRegistration() and getInstalledVersion() are currently dead code for Pi. That limits today's damage to one misleading line — but the paths are wrong and will bite whoever calls them next (getSettingsPath() would write a settings file Pi never reads).

Impact

Functionality is not broken — hooks genuinely work in this setup. I verified capture is live:

$ sqlite3 ~/.pi/context-mode/sessions/<session>.db "select count(*) from session_events;"
186
$ sqlite3 ~/.pi/context-mode/sessions/<session>.db "select count(*) from tool_calls;"
6

The wiring is the npm-package path: ~/.pi/agent/settings.jsonpackages: ["npm:context-mode"] → the package's pi.extensionsbuild/adapters/pi/extension.js. The problem is purely that the adapter (and the line doctor prints from it) describes a legacy layout instead of that one.

Suggested fix

  • getSettingsPath()join(process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent"), "settings.json") (the OMP adapter already uses PI_CODING_AGENT_DIR; that env var is unset by default, where ~/.pi/agent is the default).
  • checkPluginRegistration() → read that settings file and check packages for context-mode, which is the registration signal the README defines.
  • getInstalledVersion() → read the installed package's package.json (e.g. ~/.pi/agent/npm/node_modules/context-mode/package.json) instead of the never-existing extensions file.
  • validateHooks() message → describe the actual mechanism (package pi.extensionsbuild/adapters/pi/extension.js); drop the stale path.
  • Also update the header comment (L14–16) and tests/adapters/pi-adapter.test.ts:90 (it("settings path is ~/.pi/settings.json", ...)), which currently freeze the legacy path in place.

Happy to open a PR with this change if you agree with the direction — and equally happy to be told the legacy path is intentional for some Pi version I'm not aware of.