diff --git a/README.md b/README.md index 9107372..292dd80 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,8 @@ ArchitectureToolsHooks • - Skills + Skills • + Plugins

--- @@ -287,6 +288,8 @@ my-agent/ │ └── *.yaml|*.md # Multi-step workflow definitions ├── agents/ │ └── / # Sub-agent definitions +├── plugins/ +│ └── / # Local plugins (plugin.yaml + tools/hooks/skills) ├── hooks/ │ └── hooks.yaml # Lifecycle hook scripts ├── knowledge/ @@ -420,6 +423,166 @@ When reviewing code: Invoke via CLI: `/skill:code-review Review the auth module` +## Plugins + +Plugins are reusable extensions that can provide tools, hooks, skills, prompts, and memory layers. They follow the same git-native philosophy — a plugin is a directory with a `plugin.yaml` manifest. + +### CLI Commands + +```bash +# Install from git URL +gitclaw plugin install https://github.com/org/my-plugin.git + +# Install from local path +gitclaw plugin install ./path/to/plugin + +# Install with options +gitclaw plugin install --name custom-name --force --no-enable + +# List all discovered plugins +gitclaw plugin list + +# Enable / disable +gitclaw plugin enable my-plugin +gitclaw plugin disable my-plugin + +# Remove +gitclaw plugin remove my-plugin + +# Scaffold a new plugin +gitclaw plugin init my-plugin +``` + +| Flag | Description | +|---|---| +| `--name ` | Custom plugin name (default: derived from source) | +| `--force` | Reinstall even if already present | +| `--no-enable` | Install without auto-enabling | + +### Plugin Manifest (`plugin.yaml`) + +```yaml +id: my-plugin # Required, kebab-case +name: My Plugin +version: 0.1.0 +description: What this plugin does +author: Your Name +license: MIT +engine: ">=0.3.0" # Min gitclaw version + +provides: + tools: true # Load tools from tools/*.yaml + skills: true # Load skills from skills/ + prompt: prompt.md # Inject into system prompt + hooks: + pre_tool_use: + - script: hooks/audit.sh + description: Audit tool calls + +config: + properties: + api_key: + type: string + description: API key + env: MY_API_KEY # Env var fallback + timeout: + type: number + default: 30 + required: [api_key] + +entry: index.ts # Optional programmatic entry point +``` + +### Plugin Config in `agent.yaml` + +```yaml +plugins: + my-plugin: + enabled: true + source: https://github.com/org/my-plugin.git # Auto-install on load + version: main # Git branch/tag + config: + api_key: "${MY_API_KEY}" # Supports env interpolation + timeout: 60 +``` + +Config resolution priority: `agent.yaml config` > `env var` > `manifest default`. + +### Discovery Order + +Plugins are discovered in this order (first match wins): + +1. **Local** — `/plugins//` +2. **Global** — `~/.gitclaw/plugins//` +3. **Installed** — `/.gitagent/plugins//` + +### Programmatic Plugins + +Plugins with an `entry` field in their manifest get a full API: + +```typescript +// index.ts +import type { GitclawPluginApi } from "gitclaw"; + +export async function register(api: GitclawPluginApi) { + // Register a tool + api.registerTool({ + name: "search_docs", + description: "Search documentation", + inputSchema: { + properties: { query: { type: "string" } }, + required: ["query"], + }, + handler: async (args) => { + const results = await search(args.query); + return { text: JSON.stringify(results) }; + }, + }); + + // Register a lifecycle hook + api.registerHook("pre_tool_use", async (ctx) => { + api.logger.info(`Tool called: ${ctx.tool}`); + return { action: "allow" }; + }); + + // Add to system prompt + api.addPrompt("Always check docs before answering questions."); + + // Register a memory layer + api.registerMemoryLayer({ + name: "docs-cache", + path: "memory/docs-cache.md", + description: "Cached documentation lookups", + }); +} +``` + +**Available API methods:** + +| Method | Description | +|---|---| +| `registerTool(def)` | Register a tool the agent can call | +| `registerHook(event, handler)` | Register a lifecycle hook (`on_session_start`, `pre_tool_use`, `post_response`, `on_error`) | +| `addPrompt(text)` | Append text to the system prompt | +| `registerMemoryLayer(layer)` | Register a memory layer | +| `logger.info/warn/error(msg)` | Prefixed logging (`[plugin:id]`) | +| `pluginId` | Plugin identifier | +| `pluginDir` | Absolute path to plugin directory | +| `config` | Resolved config values | + +### Plugin Structure + +``` +my-plugin/ +├── plugin.yaml # Manifest (required) +├── tools/ # Declarative tool definitions +│ └── *.yaml +├── hooks/ # Hook scripts +├── skills/ # Skill modules +├── prompt.md # System prompt addition +└── index.ts # Programmatic entry point +``` + ## Multi-Model Support Gitclaw works with any LLM provider supported by [pi-ai](https://github.com/nicepkg/pi-ai):