omp packages

@graelo/pi-agent-switch0.2.0

Switch the main pi session between pre-defined agents, so pi-permission-system applies that agent's permission rules

graelo Published 8 hours ago MIT ~186 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

pi-agent-switch

Switch the main pi session between pre-defined agents, so @gotgenes/pi-permission-system applies that agent's permission rules.

Pick an agent and the permission system applies its agent-specific rules to the main session until you pick another. A named agent without agent-specific rules can restore the config-derived policy; see Returning to baseline.

How it works

@gotgenes/pi-permission-system resolves the active agent name in resolveAgentName (src/session/permission-session.ts), in this order:

  1. getActiveAgentName(ctx) — the most recent session entry with customType: "active_agent"
  2. getActiveAgentNameFromSystemPrompt() — the <active_agent name="..."/> system-prompt tag
  3. the last name it saw

This extension writes both channels. Switching appends the session entry (channel 1, which takes precedence) and injects the tag into the system prompt (channel 2, the documented one, as a fallback). The permission system then applies that agent's frontmatter over your config.json policy.

Agent policy enforcement is the permission system's. This extension does not interpret permission rules or prompt for individual tool calls. It has one narrow fail-closed guard: if the selected branch's identity cannot be safely reconciled with the permission system, model tool calls are blocked until you select a named agent. This guard is not a replacement for the permission system.

Compatibility

This extension does not depend on a subagent package. With nicobailon's npm package pi-subagents 0.84.0, native child prompts carry an <active_agent> tag. This does not guarantee per-agent permission enforcement: the permission-system extension must be loaded in the child, and it must be able to find a matching agent policy. In particular, foreground children do not load ambient extensions automatically, and external runners have their own behavior. Consult pi-subagents' agent documentation for child extension configuration.

The permission system looks for agent policy files by active name in its own global and project agent directories, not every location pi-subagents scans. The parent entry written by this extension is not a substitute for configuring child permissions.

Caveat: the session-entry channel is undocumented — only the prompt tag appears in the permission system's docs, so the entry is not a public integration API. The regression tests use @gotgenes/pi-permission-system 42.0.0; re-check behavior on upgrade. The prompt tag is a lower-precedence fallback, not a guaranteed replacement.

Install

pi install npm:@graelo/pi-agent-switch

Requires Pi 1.5.0 or later; tested with Pi 1.5.0 and @gotgenes/pi-permission-system 42.0.0. The permission system must be installed separately; without it, switching still records the agent but nothing enforces it.

Agents

This extension reads top-level agent files from these directories, lowest precedence first:

  1. <agent-dir>/agents/*.md
  2. <cwd>/.pi/agents/*.md

The switcher uses the filename stem as the agent name. For shared definitions, use a matching frontmatter name and filename (for example reviewer.md and name: reviewer), without package qualification. A project definition shadows a global one in the picker, and enabled: false disables it there. The permission system composes agent rules from both global and project files; shadowing in the picker does not suppress global permission rules.

Nicobailon's pi-subagents also discovers nested files, builtins, package agents, legacy .agents files, and configurable scan roots. Those are not all available in this switcher or resolvable by the permission system. This extension only reads definitions; it never writes them.

The project tier is skipped when the project is untrusted. Agent frontmatter must be valid YAML with no duplicate keys. Invalid or unreadable definitions are marked invalid and cannot be selected; an invalid project file still shadows the global file of the same name. If a recorded agent becomes invalid, model tool calls are blocked until a valid agent is selected. Definitions without frontmatter remain supported.

The switcher validates inheritSkills (a YAML boolean) and skills and skillPath (comma-separated strings or lists of non-empty strings). These fields determine the main-session skill catalogue as described below.

An agent file contributes agent-specific rules through its permission: block. The picker marks files without one with [no permission block], and switching to one warns. Another scope with the same name may still contribute rules:

---
name: reviewer
description: Read-only review
permission:
  read: allow
  write: deny
  edit: deny
  bash:
    "*": ask
---

You are reviewing, not implementing.

Usage

Action Effect
Alt+Tab (default) Cycle through named agents
/agent Open a picker
/agent <name> Switch directly (tab-completes)
/agent-skills Inspect the last run's skill-resolution snapshot

The status bar shows ⬢ <agent>. A new session may start without a selection, but there is no clear action: select a named baseline instead. On /tree, the agent and hint state follow the selected branch. A valid configured default is used when that branch has no recorded choice.

If a branch has no safely resolvable identity after a previous selection, or its recorded agent is missing, disabled, or a legacy null entry, the status shows ⚠ agent unresolved and model tool calls are blocked. Use /agent or Alt+Tab to select a named agent and resume. A genuinely fresh session with no selection can use the baseline policy normally. The guard covers model tool calls, not shell commands entered directly by the user.

Choices survive /resume and /reload. Because the permission system scans all session entries rather than just the active branch, the switcher records a reconciliation entry when needed so both extensions resolve the same name.

By default, the next agent run after a switch receives a one-time, hidden model-facing message naming the selected agent and reminding it to reassess available tools and permissions. Several switches before a run produce one hint for the final selection; returning to the original agent produces none. Switching alone does not start a run. The hint survives reload before delivery and is stored in the conversation after delivery. It does not describe or enforce specific permissions. Set switchHint to false to disable it, independently of applySystemPrompt.

Agent skill selection

For the detailed field, resolution and failure contract, see the skill-selection specification.

Agent definitions can select the model-visible skill catalogue per run:

---
inheritSkills: false
skillPath: [../video-skills]
skills: [manimce-best-practices, explainer-video]
---

inheritSkills defaults to true. false starts with an empty catalogue; skills adds named selections, and an empty list selects none. skillPath contains discovery directories or Markdown skill files, resolved relative to the agent definition, not the session's working directory. It does not add all skills in those paths. skills and skillPath accept YAML string lists or comma-separated strings. Paths do not expand shell variables or ~.

Selected private skills take precedence over ambient skills with the same name; an absent private name falls back to the incoming ambient catalogue. Invalid roots, ambiguous or broken selected skills, and skills that disable model invocation are errors. If a private candidate cannot be classified, selection is unresolved because its name could collide with a selected skill. This is deliberately stricter than pi-subagents' child selection, which may fall back after an unreadable local candidate. The switcher checks known problems before a switch; the incoming ambient catalogue is available only at run time. If resolution fails then, it keeps the recorded agent, reports the error, empties the structured catalogue, aborts the run and blocks model tool calls. Repair the skill or select another agent; the next run rechecks the files. /agent-skills shows the last resolution, including names, paths and diagnostics, or reports that it is unresolved. It is a snapshot, not a live view: switching, reload, file changes, later extensions and forced prompts can make it stale or inaccurate.

This changes automatic model-facing discovery, not access control or conversation isolation. Prior messages and instructions remain visible, filesystem permissions do not change, and Pi's /skill:name commands are not updated: private skills may lack a command and filtered ambient skills may remain invocable. Other extensions can change the catalogue afterward, and a forced system prompt can mask it. Cancellation was verified with Pi 1.5.0's OpenAI Responses adapter in simulated mode bindings and actual TUI, print, JSON and RPC entry points; OpenAI Completions in print and JSON; and Anthropic Messages in print, JSON and RPC. These checks used local endpoints. A provider that ignores an abort signal may still send a request. A fresh session is the predictable choice when switching skill ecosystems.

Returning to baseline

Create <agent-dir>/agents/baseline.md with no permission: block and no prompt body:

---
name: baseline
description: Config-derived permissions
---

Select it with /agent baseline. The permission system then uses its global and project config-derived policy instead of the previous agent's rules. Neither the global nor project baseline.md may contribute agent-specific rules for this to hold; runtime approvals and other permission-system behavior may still apply. The switcher warns about the missing block, which is expected.

/agent none is not a clear operation. The permission system can retain its last known agent when given a null entry, so clearing cannot safely promise baseline permissions. An actual definition named none is just another agent.

Config

Optional, resolved by @graelo/pi-ext-config:

Tier Path
Project <repo-root>/.pi/extensions/pi-agent-switch/config.json
Global <agent-dir>/extensions/pi-agent-switch/config.json
{
  "defaultAgent": "reviewer",
  "applySystemPrompt": true,
  "switchHint": true,
  "shortcut": "alt+tab"
}
Key Default Effect
defaultAgent null Agent for a branch with no recorded choice; a valid default is recorded when applied. An existing choice wins, including a legacy null entry.
applySystemPrompt true Also append the agent's own system prompt (its file body) to the session's.
switchHint true Send a one-time model-facing reminder on the next run after a switch.
shortcut "alt+tab" Global-only Pi key identifier for cycling agents; set to null to disable the shortcut.

Loaded with shallow-merge, so a project config can set one key and inherit the rest. The shortcut is the exception: it is read only from the global config because Pi registers shortcuts before project trust is available. Run /reload after changing it. Invalid values disable the shortcut and produce a warning. Use Pi's key syntax and check /hotkeys for conflicts; a terminal or multiplexer may also intercept a key.

applySystemPrompt only ever appends. prompt_mode: replace is deliberately not honoured in the main session: replacing pi's assembled system prompt would discard its tool instructions along with everything else. Set it to false to switch permissions only and leave agent body prompting alone; the identity tag is still added.

Pi renders the agent tag and body in its structured append section, after existing appended text but before project context and skills. Another extension that forces a complete system prompt can mask these additions. An earlier forced prompt produces a warning; a later override cannot be detected here. The session entry remains the primary permission identity channel.

Terminal bindings

Pi does not assign Alt+Tab by default; Shift+Tab cycles thinking level. On macOS, Alt+Tab is Option+Tab. Terminal and multiplexer key handling varies; /hotkeys shows whether Pi registered the shortcut, and pressing it verifies the keystroke reaches Pi. If another application intercepts it, configure a different shortcut.

Layout

src/index.ts    extension entry: events, shortcut, command
src/agents.ts   agent discovery, frontmatter parsing

License

MIT