Skip to content

Commit 5c330d9

Browse files
Scaffold gitclaw agent (#16)
1 parent f888971 commit 5c330d9

1 file changed

Lines changed: 164 additions & 1 deletion

File tree

README.md

Lines changed: 164 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
<a href="#architecture">Architecture</a> &bull;
2424
<a href="#tools">Tools</a> &bull;
2525
<a href="#hooks">Hooks</a> &bull;
26-
<a href="#skills">Skills</a>
26+
<a href="#skills">Skills</a> &bull;
27+
<a href="#plugins">Plugins</a>
2728
</p>
2829

2930
---
@@ -287,6 +288,8 @@ my-agent/
287288
│ └── *.yaml|*.md # Multi-step workflow definitions
288289
├── agents/
289290
│ └── <name>/ # Sub-agent definitions
291+
├── plugins/
292+
│ └── <name>/ # Local plugins (plugin.yaml + tools/hooks/skills)
290293
├── hooks/
291294
│ └── hooks.yaml # Lifecycle hook scripts
292295
├── knowledge/
@@ -420,6 +423,166 @@ When reviewing code:
420423

421424
Invoke via CLI: `/skill:code-review Review the auth module`
422425

426+
## Plugins
427+
428+
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.
429+
430+
### CLI Commands
431+
432+
```bash
433+
# Install from git URL
434+
gitclaw plugin install https://github.com/org/my-plugin.git
435+
436+
# Install from local path
437+
gitclaw plugin install ./path/to/plugin
438+
439+
# Install with options
440+
gitclaw plugin install <source> --name custom-name --force --no-enable
441+
442+
# List all discovered plugins
443+
gitclaw plugin list
444+
445+
# Enable / disable
446+
gitclaw plugin enable my-plugin
447+
gitclaw plugin disable my-plugin
448+
449+
# Remove
450+
gitclaw plugin remove my-plugin
451+
452+
# Scaffold a new plugin
453+
gitclaw plugin init my-plugin
454+
```
455+
456+
| Flag | Description |
457+
|---|---|
458+
| `--name <name>` | Custom plugin name (default: derived from source) |
459+
| `--force` | Reinstall even if already present |
460+
| `--no-enable` | Install without auto-enabling |
461+
462+
### Plugin Manifest (`plugin.yaml`)
463+
464+
```yaml
465+
id: my-plugin # Required, kebab-case
466+
name: My Plugin
467+
version: 0.1.0
468+
description: What this plugin does
469+
author: Your Name
470+
license: MIT
471+
engine: ">=0.3.0" # Min gitclaw version
472+
473+
provides:
474+
tools: true # Load tools from tools/*.yaml
475+
skills: true # Load skills from skills/
476+
prompt: prompt.md # Inject into system prompt
477+
hooks:
478+
pre_tool_use:
479+
- script: hooks/audit.sh
480+
description: Audit tool calls
481+
482+
config:
483+
properties:
484+
api_key:
485+
type: string
486+
description: API key
487+
env: MY_API_KEY # Env var fallback
488+
timeout:
489+
type: number
490+
default: 30
491+
required: [api_key]
492+
493+
entry: index.ts # Optional programmatic entry point
494+
```
495+
496+
### Plugin Config in `agent.yaml`
497+
498+
```yaml
499+
plugins:
500+
my-plugin:
501+
enabled: true
502+
source: https://github.com/org/my-plugin.git # Auto-install on load
503+
version: main # Git branch/tag
504+
config:
505+
api_key: "${MY_API_KEY}" # Supports env interpolation
506+
timeout: 60
507+
```
508+
509+
Config resolution priority: `agent.yaml config` > `env var` > `manifest default`.
510+
511+
### Discovery Order
512+
513+
Plugins are discovered in this order (first match wins):
514+
515+
1. **Local** — `<agent-dir>/plugins/<name>/`
516+
2. **Global** — `~/.gitclaw/plugins/<name>/`
517+
3. **Installed** — `<agent-dir>/.gitagent/plugins/<name>/`
518+
519+
### Programmatic Plugins
520+
521+
Plugins with an `entry` field in their manifest get a full API:
522+
523+
```typescript
524+
// index.ts
525+
import type { GitclawPluginApi } from "gitclaw";
526+
527+
export async function register(api: GitclawPluginApi) {
528+
// Register a tool
529+
api.registerTool({
530+
name: "search_docs",
531+
description: "Search documentation",
532+
inputSchema: {
533+
properties: { query: { type: "string" } },
534+
required: ["query"],
535+
},
536+
handler: async (args) => {
537+
const results = await search(args.query);
538+
return { text: JSON.stringify(results) };
539+
},
540+
});
541+
542+
// Register a lifecycle hook
543+
api.registerHook("pre_tool_use", async (ctx) => {
544+
api.logger.info(`Tool called: ${ctx.tool}`);
545+
return { action: "allow" };
546+
});
547+
548+
// Add to system prompt
549+
api.addPrompt("Always check docs before answering questions.");
550+
551+
// Register a memory layer
552+
api.registerMemoryLayer({
553+
name: "docs-cache",
554+
path: "memory/docs-cache.md",
555+
description: "Cached documentation lookups",
556+
});
557+
}
558+
```
559+
560+
**Available API methods:**
561+
562+
| Method | Description |
563+
|---|---|
564+
| `registerTool(def)` | Register a tool the agent can call |
565+
| `registerHook(event, handler)` | Register a lifecycle hook (`on_session_start`, `pre_tool_use`, `post_response`, `on_error`) |
566+
| `addPrompt(text)` | Append text to the system prompt |
567+
| `registerMemoryLayer(layer)` | Register a memory layer |
568+
| `logger.info/warn/error(msg)` | Prefixed logging (`[plugin:id]`) |
569+
| `pluginId` | Plugin identifier |
570+
| `pluginDir` | Absolute path to plugin directory |
571+
| `config` | Resolved config values |
572+
573+
### Plugin Structure
574+
575+
```
576+
my-plugin/
577+
├── plugin.yaml # Manifest (required)
578+
├── tools/ # Declarative tool definitions
579+
│ └── *.yaml
580+
├── hooks/ # Hook scripts
581+
├── skills/ # Skill modules
582+
├── prompt.md # System prompt addition
583+
└── index.ts # Programmatic entry point
584+
```
585+
423586
## Multi-Model Support
424587

425588
Gitclaw works with any LLM provider supported by [pi-ai](https://github.com/nicepkg/pi-ai):

0 commit comments

Comments
 (0)