Skip to content

Plugins

letscode's plugin system is built on pluggy. A plugin is a Python package that registers tools, slash commands, skills, frontends, or lifecycle hooks via standard Python entry points. letscode discovers plugins at startup, calls their registration hooks, and lets the lifecycle hooks intercede during agent turns.

What you can register

Five extension types:

Type Hook What it adds
Tool letscode_register_tools LLM-callable tools (e.g. read, write).
Command letscode_register_commands Slash commands (e.g. /help, /skills).
Skill letscode_register_skills Skill source dirs or inline skills.
Frontend letscode_register_frontends Named frontend factories.
Lifecycle hook @hookimpl on any of the lifecycle hookspecs Cross-cutting behavior.

The first four are named things added to a registry. The fifth is behavior layered on the agent loop. See Extension model for the full hook inventory.

TL;DR — your first plugin

mypkg/plugin.py
import pluggy
from pydantic import BaseModel

from letscode.agent.tools import ToolContext, ToolResult, tool
from letscode.llm.types import TextPart

hookimpl = pluggy.HookimplMarker("letscode")


class _GreetParams(BaseModel):
    name: str


@tool(name="greet", description="Say hello to someone.")
async def _greet(params: _GreetParams, ctx: ToolContext) -> ToolResult:
    del ctx
    return ToolResult(content=[TextPart(text=f"Hello, {params.name}!")])


@hookimpl
def letscode_register_tools(registry):
    registry.add(_greet)
pyproject.toml
[project.entry-points.letscode]
my_plugin = "mypkg.plugin"
pip install -e .          # or: pip install mypkg
letscode "say hi to alice"

The LLM can now call the greet tool. That's the whole story for tools.

For everything else — commands, skills, frontends, lifecycle hooks, message types, packaging, testing — see the authoring guide.