AFT issue: OMP (oh-my-pi) is not a first-class harness — tools mount under xd:// and prompt-injection paths degrade
Summary
@cortexkit/aft-pi targets upstream Pi (@earendil-works/pi-coding-agent). It works on OMP (oh-my-pi, a Pi-compatible harness) only because OMP implements a large subset of the Pi extension API — but two Pi-specific assumptions silently degrade the experience on OMP. Reporting both with evidence, plus what a fix would look like.
Repro environment: OMP 18.x (@oh-my-pi/pi-coding-agent), @cortexkit/aft-pi@0.55.1, hoist_builtin_tools: false, tool_surface: "all", semantic_search: true.
1. All AFT tools mount under xd:// instead of registering top-level
Mechanism
OMP decides per tool whether it ships in the request's tools array (top-level) or mounts as an xd:// device invoked via write xd://<tool>:
isMountableUnderXdev (oh-my-pi packages/coding-agent/src/tools/xdev.ts:84-87): mounts everything with loadMode === "discoverable".
- Extension-registered tools resolve their
loadMode in RegisteredToolAdapter (extensibility/extensions/wrapper.ts:48) via defaultLoadModeForToolName (tools/essential-tools.ts:42-45): an explicitly declared mode wins; undeclared → "discoverable" unless the name is one of 10 hardcoded essentials (read, write, bash, edit, glob, eval, task, hub, learn, manage_skill).
packages/pi-plugin/src never passes loadMode to registerTool (zero occurrences in dist/index.js and in the current source tree). Result: every aft_*/ast_grep_* tool mounts under xd:// on OMP, regardless of config.
On OpenCode the same tools are all top-level (OpenCode has no xdev mounting and its own hoisting model), and on upstream Pi there is no mount mechanism at all — so this gap is OMP-specific and invisible to the author's testing surface.
Impact
- Every AFT call costs a
write xd://aft_zoom round-trip instead of a direct tool call.
- AFT's carefully tuned
promptSnippet/promptGuidelines fields (see issue 2) never reach the system prompt on OMP: the device catalog shows a one-line summary (first description line, capped at 200 bytes for third-party tools — xdev.ts:186-205), not the guidelines.
- Partial workaround exists user-side (
tools.xdevInlineDevices: ["aft_*", "ast_grep*"] inlines docs+schema into the prompt), but calls still ride the device transport, and nothing makes the tools top-level.
Suggested fix
Declare presentation intent on registration, falling back sensibly per harness:
pi.registerTool(withPathAliasPreparation({
name: "aft_zoom",
loadMode: "essential", // or a config-gated choice
...
}))
Since OMP honors a declared loadMode and Pi (upstream) ignores unknown fields, adding loadMode: "essential" to the register calls is backward-compatible with both. A config gate ("tool_presentation": "top_level" | "host_default", default host_default) would let users choose without forking.
2. System-prompt injection works, but per-tool guidance fields are dead on OMP
What AFT injects today
- Workflow hints block:
packages/pi-plugin/src/workflow-hints.ts registers a before_agent_start handler that appends the "IMPORTANT NOTICE about your tools" block (bash-compression tips, code-exploration routing, aft_inspect guidance, callgraph ops, background-bash rules). Gated by absentTools/toolSurface/hoistBuiltins so absent tools aren't advertised (workflow-hints.ts:203-227).
- Per-tool guidance:
promptSnippet and promptGuidelines on registered tools (tools/hoisted.ts:6-10 — "teach the model our argument shape in Pi's system prompt"; tools/bash.ts:489-498 — the "DO NOT use bash for code search … use aft_search" steer).
- Tool-result steering:
withBashHints (index.ts:37165 in dist) appends grep/rewrite hints to bash output, and the Rust bridge emits a grep-rewrite footer steered by the aft_search_registered configure flag (index.ts:683-688).
The OMP gap
Upstream Pi renders promptSnippet/promptGuidelines into its system prompt (that's why the fields exist — hoisted.ts:7-8: "Pi's built-ins use generic one-liners otherwise"). OMP does not consume them: its system-prompt builder uses tool description only; promptGuidelines appears exactly once in OMP's codebase as an unused type field (extensibility/extensions/types.ts:696), and promptSnippet has zero references. AFT's bash-search prohibition and per-tool usage rules therefore never reach the model's system prompt on OMP.
The before_agent_start chain DOES work on OMP (OMP fires the event with systemPrompt: string[] and chains string results — extensibility/extensions/runner.ts:1730-1755 normalizes a returned string into the array), so the workflow-hints block lands. That's why the symptoms are subtle: routing guidance arrives, but the per-tool argument-shape teaching and the bash-search STOP steer don't. Net effect on OMP: the agent sees AFT's tool names and descriptions but none of the per-tool behavioral guidance that makes the surface feel first-class on Pi/OpenCode.
Suggested fix
Either (a) move critical per-tool rules (the bash-search STOP steer especially) into the workflow-hints block, which is harness-portable, or (b) accept a small per-harness shim: on OMP, fold promptSnippet/promptGuidelines into each tool's description at registration time (OMP renders descriptions verbatim). (b) is a ~10-line change in the shared registration helper (withPathAliasPreparation or the surface registry) gated on harness detection.
3. Harness awareness today
The repo has zero OMP-specific code: no oh-my-pi/OMP references in packages/ (the only mentions are hashline-oracle provenance notes in crates/ — credit for the hashline format OMP authored); no OMP harness detection in the pi-plugin; README.md:52,66-67 documents exactly two harnesses (OpenCode, Pi). The author's own design makes this rational: the adapters are deliberately thin, per-harness, and hoisting-centric; OMP's mount model is a third presentation regime the adapter never had to consider. This issue is meant to close that visibility gap, not to relitigate the architecture.
Happy to test any fix against OMP — we run OMP as the primary harness with hoist_builtin_tools: false + full aft_* surface daily.
AFT issue: OMP (oh-my-pi) is not a first-class harness — tools mount under xd:// and prompt-injection paths degrade
Summary
@cortexkit/aft-pitargets upstream Pi (@earendil-works/pi-coding-agent). It works on OMP (oh-my-pi, a Pi-compatible harness) only because OMP implements a large subset of the Pi extension API — but two Pi-specific assumptions silently degrade the experience on OMP. Reporting both with evidence, plus what a fix would look like.Repro environment: OMP 18.x (
@oh-my-pi/pi-coding-agent),@cortexkit/aft-pi@0.55.1,hoist_builtin_tools: false,tool_surface: "all",semantic_search: true.1. All AFT tools mount under
xd://instead of registering top-levelMechanism
OMP decides per tool whether it ships in the request's tools array (top-level) or mounts as an
xd://device invoked viawrite xd://<tool>:isMountableUnderXdev(oh-my-pipackages/coding-agent/src/tools/xdev.ts:84-87): mounts everything withloadMode === "discoverable".loadModeinRegisteredToolAdapter(extensibility/extensions/wrapper.ts:48) viadefaultLoadModeForToolName(tools/essential-tools.ts:42-45): an explicitly declared mode wins; undeclared →"discoverable"unless the name is one of 10 hardcoded essentials (read, write, bash, edit, glob, eval, task, hub, learn, manage_skill).packages/pi-plugin/srcnever passesloadModetoregisterTool(zero occurrences indist/index.jsand in the current source tree). Result: everyaft_*/ast_grep_*tool mounts underxd://on OMP, regardless of config.On OpenCode the same tools are all top-level (OpenCode has no xdev mounting and its own hoisting model), and on upstream Pi there is no mount mechanism at all — so this gap is OMP-specific and invisible to the author's testing surface.
Impact
write xd://aft_zoomround-trip instead of a direct tool call.promptSnippet/promptGuidelinesfields (see issue 2) never reach the system prompt on OMP: the device catalog shows a one-line summary (first description line, capped at 200 bytes for third-party tools —xdev.ts:186-205), not the guidelines.tools.xdevInlineDevices: ["aft_*", "ast_grep*"]inlines docs+schema into the prompt), but calls still ride the device transport, and nothing makes the tools top-level.Suggested fix
Declare presentation intent on registration, falling back sensibly per harness:
Since OMP honors a declared
loadModeand Pi (upstream) ignores unknown fields, addingloadMode: "essential"to the register calls is backward-compatible with both. A config gate ("tool_presentation": "top_level" | "host_default", default host_default) would let users choose without forking.2. System-prompt injection works, but per-tool guidance fields are dead on OMP
What AFT injects today
packages/pi-plugin/src/workflow-hints.tsregisters abefore_agent_starthandler that appends the "IMPORTANT NOTICE about your tools" block (bash-compression tips, code-exploration routing,aft_inspectguidance, callgraph ops, background-bash rules). Gated byabsentTools/toolSurface/hoistBuiltinsso absent tools aren't advertised (workflow-hints.ts:203-227).promptSnippetandpromptGuidelineson registered tools (tools/hoisted.ts:6-10— "teach the model our argument shape in Pi's system prompt";tools/bash.ts:489-498— the "DO NOT use bash for code search … use aft_search" steer).withBashHints(index.ts:37165in dist) appends grep/rewrite hints to bash output, and the Rust bridge emits a grep-rewrite footer steered by theaft_search_registeredconfigure flag (index.ts:683-688).The OMP gap
Upstream Pi renders
promptSnippet/promptGuidelinesinto its system prompt (that's why the fields exist —hoisted.ts:7-8: "Pi's built-ins use generic one-liners otherwise"). OMP does not consume them: its system-prompt builder uses tooldescriptiononly;promptGuidelinesappears exactly once in OMP's codebase as an unused type field (extensibility/extensions/types.ts:696), andpromptSnippethas zero references. AFT's bash-search prohibition and per-tool usage rules therefore never reach the model's system prompt on OMP.The
before_agent_startchain DOES work on OMP (OMP fires the event withsystemPrompt: string[]and chains string results —extensibility/extensions/runner.ts:1730-1755normalizes a returned string into the array), so the workflow-hints block lands. That's why the symptoms are subtle: routing guidance arrives, but the per-tool argument-shape teaching and the bash-search STOP steer don't. Net effect on OMP: the agent sees AFT's tool names and descriptions but none of the per-tool behavioral guidance that makes the surface feel first-class on Pi/OpenCode.Suggested fix
Either (a) move critical per-tool rules (the bash-search STOP steer especially) into the workflow-hints block, which is harness-portable, or (b) accept a small per-harness shim: on OMP, fold
promptSnippet/promptGuidelinesinto each tool'sdescriptionat registration time (OMP renders descriptions verbatim). (b) is a ~10-line change in the shared registration helper (withPathAliasPreparationor the surface registry) gated on harness detection.3. Harness awareness today
The repo has zero OMP-specific code: no
oh-my-pi/OMP references inpackages/(the only mentions are hashline-oracle provenance notes incrates/— credit for the hashline format OMP authored); no OMP harness detection in the pi-plugin;README.md:52,66-67documents exactly two harnesses (OpenCode, Pi). The author's own design makes this rational: the adapters are deliberately thin, per-harness, and hoisting-centric; OMP's mount model is a third presentation regime the adapter never had to consider. This issue is meant to close that visibility gap, not to relitigate the architecture.Happy to test any fix against OMP — we run OMP as the primary harness with
hoist_builtin_tools: false+ fullaft_*surface daily.