Pi Agent Plugin Development Guide | Generated by AI

Home 2026.07

Question: How do I write a plugin like this for the Pi Agent?

Answer:

The plugin you showed has a very common architecture:

User types:
/note --title "..."

        │
        ▼
Plugin loader
        │
        ▼
register(ctx)
        │
        ▼
ctx.register_command(...)
        │
        ▼
handler(raw_args)
        │
        ▼
access conversation history
        │
        ▼
process data
        │
        ▼
return string to CLI

The key ideas are:


Minimal plugin API

Suppose Pi Agent exposes something like

class PluginContext:
    agent
    cli

    def register_command(
        self,
        name,
        handler,
        description="",
        args_hint=""
    ):
        ...

Then every plugin only needs

my_plugin/
    __init__.py
    plugin.yaml

init.py

from pathlib import Path

_ctx = None

def hello(args):
    return f"Hello {args}"

def register(ctx):
    global _ctx
    _ctx = ctx

    ctx.register_command(
        "hello",
        handler=hello,
        description="Say hello",
        args_hint="<name>"
    )

Then

/hello OpenAI

becomes

Hello OpenAI

plugin.yaml

name: hello
version: 1.0
entry: __init__.py
description: Example plugin

The loader reads

~/.pi/plugins/
    hello/
        plugin.yaml
        __init__.py

and imports

plugin.register(ctx)

Accessing history

Exactly like Hermes.

def last_assistant():
    history = _ctx.cli.history

    assistants = [
        m
        for m in history
        if m["role"] == "assistant"
    ]

    return assistants[-1]["content"]

Now your plugin can summarize

def summary(args):
    text = last_assistant()

    return text[:300]

Calling agent APIs

Instead of touching files directly

_ctx.agent.add_note(...)

or

_ctx.agent.memory.save(...)

or

_ctx.agent.vector_store.insert(...)

For example

def remember(args):
    _ctx.agent.memory.save(args)
    return "Saved."

Register multiple commands

def register(ctx):

    ctx.register_command(
        "note",
        note_handler,
        description="Save note"
    )

    ctx.register_command(
        "summary",
        summary_handler,
        description="Summarize"
    )

    ctx.register_command(
        "clip",
        clip_handler,
        description="Copy response"
    )

Event hooks (recommended)

Rather than only slash commands, expose lifecycle hooks.

def on_start(ctx):
    ...

def on_before_llm(prompt):
    ...

def on_after_llm(response):
    ...

def on_exit():
    ...

Then a plugin can automatically archive every answer without requiring /note.

Example:

def on_after_llm(response):

    if len(response) > 500:
        save(response)

Suggested Pi Agent plugin interface

class PluginContext:

    config

    logger

    history

    workspace

    cache_dir

    register_command(...)

    register_hook(...)

    run_shell(...)

    ask_llm(...)

    current_model

    conversation

    clipboard

    notify()

    storage

This is roughly the level of abstraction used by mature agent frameworks.


Example note plugin

def note(args):

    text = _ctx.history.last_assistant()

    _ctx.storage.enqueue(
        queue="notes",
        content=text,
        title=args
    )

    return "Queued."

Notice how it avoids reaching into private fields like:

_ctx._manager._cli_ref

which tightly couples the plugin to internal implementation details. Exposing stable APIs such as ctx.history.last_assistant() and ctx.storage.enqueue() makes plugins easier to write, test, and keep compatible across Pi Agent versions.

References:


Generated by AI. Curating and sharing still takes effort. If you find it useful, feel free to donate. WeChat: @lzwjavaWeChat QR · X: @lzwjava · Say hi 👋

Back Donate