@openwaggle/pi-waggle
Run two configurable Pi agents in alternating turns until they reach consensus or a safety limit.
@openwaggle/pi-waggle adds a structured two-agent collaboration loop to Pi.
What Waggle Mode Does
Waggle mode gives the same task to two configurable agents and lets them alternate turns in one Pi session. Each agent sees the work already produced, can use Pi’s normal tools, and contributes from a different role. The loop stops when the agents reach consensus, the configured turn safety limit is reached, the user stops it, or an error prevents another turn.
For example, one agent can implement a change while another reviews it, an attacker can probe a design while a defender hardens it, or an advocate and critic can test competing approaches. Use Waggle mode when a task benefits from iteration and opposing viewpoints. Standard Pi mode is usually faster and cheaper for simple questions or one-step edits.
The package includes @openwaggle/waggle-core, registers /waggle and /standard, renders each turn with Pi-native UI, and persists mode state as Pi custom entries.
Install In Pi
Install the extension for your user:
pi install npm:@openwaggle/pi-waggle
Install it only for the current project:
pi install npm:@openwaggle/pi-waggle -l
Try it for one run without keeping it installed:
pi -e npm:@openwaggle/pi-waggle
Pi installs the package and provides its Pi SDK peer dependencies. After installation, run /waggle to choose or configure a preset.
If you are importing the package APIs into another project instead of installing the Pi extension, use your package manager:
@earendil-works/pi-ai, @earendil-works/pi-coding-agent, and @earendil-works/pi-tui are host-provided peer dependencies. Application developers should install the Pi versions used by their host.
Pi users normally install @openwaggle/pi-waggle alone for Waggle mode. Install @openwaggle/waggle-core directly only when your code imports core helpers itself.
Pi Extension Entry
The ./extension subpath exposes the default Pi extension factory:
import piWaggle from '@openwaggle/pi-waggle/extension'
export default piWaggle
The package manifest also declares the built Pi extension entry so Pi package loading can discover it from the installed package.
Commands
The default extension registers:
| Command | Behavior |
|---|---|
/waggle | Opens the default Waggle control flow or enables a preset. |
/waggle <preset-id> <prompt> | Enables the preset and starts from the provided prompt. |
/waggle off | Disables Waggle mode for the current branch. |
/standard | Disables Waggle mode for the current branch. |
Command parsing helpers are also exported:
import { parsePiWaggleCommandArgs } from '@openwaggle/pi-waggle/commands'
const intent = parsePiWaggleCommandArgs('code-review review this diff')
Runtime State And Messages
Pi Waggle persists branch mode state in a pi-waggle.mode-state custom entry. Turn and user-request content use custom messages. Both use identifiers under the pi-waggle.* namespace:
import {
PI_WAGGLE_MODE_STATE_CUSTOM_TYPE,
PI_WAGGLE_TURN_CUSTOM_TYPE,
PI_WAGGLE_USER_REQUEST_CUSTOM_TYPE,
parsePiWaggleModeState,
parsePiWaggleTurnDetails,
} from '@openwaggle/pi-waggle/protocol'
Use these helpers when projecting or rendering Pi Waggle state. Do not seed a parallel metadata tree outside Pi session data.
Custom Loop Integration
Advanced Pi integrations can use the loop helpers directly when they need custom metadata, message creation, or completion handling:
import { createPiWaggleExtension } from '@openwaggle/pi-waggle/loop'
import type { WaggleConfig } from '@openwaggle/waggle-core'
export function createCustomWaggle(config: WaggleConfig) {
return createPiWaggleExtension({
config,
createTurnMetadata: ({ turnNumber, agentIndex }) => ({ turnNumber, agentIndex }),
buildTurnMessage: ({ turn }) => ({
customType: 'example.waggle-turn',
content: `Turn ${String(turn.turnNumber + 1)}: ${turn.agent.label}`,
display: false,
details: { turnNumber: turn.turnNumber, agentLabel: turn.agent.label },
}),
onTurnComplete: () => ({ continue: true }),
})
}
The helper returns a controller. Register its factory as a Pi extension factory and await done for loop completion. The default turn-model resolver requires an explicit provider-qualified model. To handle $inherit, provide your own resolveTurnModel callback.
Most users should start with the default extension export, which handles inherited model selection. Use loop helpers when embedding Waggle into a custom Pi package.
Boundary Rules
@openwaggle/pi-waggle is Pi-specific. It may import Pi SDK packages and @openwaggle/waggle-core, but it should not be used as an OpenWaggle renderer dependency or browser-only extension UI package.
For runtime-neutral policy, use @openwaggle/waggle-core. For OpenWaggle visual extensions, use @openwaggle/extension-sdk.
Compatibility
| Requirement | Supported line |
|---|---|
| Node.js | 22.19 and newer |
| Pi coding agent | Host-provided peer; match your host’s SDK version |
| Pi TUI | Host-provided peer; match your host’s TUI version |
| Module format | ESM and CommonJS |
| Pi Waggle documentation | 0.1 |
The peer declarations accept any version, but that is not a guarantee of compatibility with every Pi release. The repository dependency catalog records the versions used by the current source integration.
Reference And Support
Troubleshooting
Pi does not discover the extension. Install the package in the Pi package environment and confirm the package manifest exposes ./dist/extension.js through its pi.extensions entry.
Commands render but state does not persist. Preserve pi-waggle.mode-state custom entries as well as turn and user-request custom messages in Pi session data. Saving only messages loses the persisted mode state.
Peer dependency warnings appear. Install the Pi coding-agent and TUI versions used by your host. The package’s wildcard peer declarations do not select those versions for you.
There are no migrations within the 0.1 documentation line. Future incompatible changes will receive a new versioned documentation line and migration guide.