Skip to content

Latest commit

 

History

History
254 lines (188 loc) · 6.59 KB

File metadata and controls

254 lines (188 loc) · 6.59 KB

gRPC Plugin Development Guide

gRPC plugins allow you to extend ggcode with custom tools written in any language. Unlike Go .so plugins, gRPC plugins run as independent processes and have zero version coupling with the host.

Reference Implementations

Ready-to-use demo plugins in three languages:

Language Repo Tools
Go ggcode-plugin-demo-go timestamp, uuid
Python ggcode-plugin-demo-python weather, calc
Node.js ggcode-plugin-demo-node base64_encode, base64_decode, hash

Quick Start

1. Clone a demo

# Go
git clone https://github.com/topcheer/ggcode-plugin-demo-go.git
cd ggcode-plugin-demo-go
go build -o ggcode-plugin-demo .

# Python
git clone https://github.com/topcheer/ggcode-plugin-demo-python.git
cd ggcode-plugin-demo-python
pip install -r requirements.txt
./generate_proto.sh

# Node.js
git clone https://github.com/topcheer/ggcode-plugin-demo-node.git
cd ggcode-plugin-demo-node
npm install && npm run build

2. Install

# Go
ggcode plugin install time-uuid-tools $(pwd)/ggcode-plugin-demo

# Python
ggcode plugin install weather-calc python $(pwd)/plugin.py

# Node.js
ggcode plugin install crypto-tools node $(pwd)/dist/plugin.js

3. Verify

ggcode plugin list

Restart ggcode — the agent can now use the plugin's tools.

CLI Commands

Install

ggcode plugin install <name> <command...> [--env KEY=VALUE ...] [--type grpc|command]

Examples:

# Install a Go binary
ggcode plugin install my-tools /path/to/binary

# Install a Python plugin
ggcode plugin install jira-tools python -m my_jira_plugin --env JIRA_TOKEN=xxx

# Install with multiple env vars
ggcode plugin install api-tools ./bin/api-tool --env API_KEY=secret --env DEBUG=true

List

ggcode plugin list

Uninstall

ggcode plugin uninstall <name>

Test (verify plugin can start)

ggcode plugin test <name>

How It Works

ggcode host process
  │
  ├── starts plugin subprocess (your binary)
  ├── connects via gRPC (Unix domain socket)
  ├── calls ListTools() → registers tools in the agent's tool registry
  ├── LLM calls tool → host calls Execute() via gRPC → returns result
  └── on shutdown: calls Shutdown() → SIGTERM → grace period → SIGKILL

Manual Configuration

You can also edit ggcode.yaml directly:

plugins:
  - name: my-plugin
    type: grpc
    command: ["./bin/my-plugin"]       # path to your plugin binary
    env:                                # optional environment variables
      API_KEY: "${MY_API_KEY}"
      DEBUG: "true"

Go SDK Quick Start

1. Create a module

mkdir my-plugin && cd my-plugin
go mod init my-plugin

2. Add SDK dependency

go get github.com/topcheer/ggcode/sdk/plugin

3. Implement the plugin

package main

import (
    "encoding/json"
    "fmt"
    "github.com/topcheer/ggcode/sdk/plugin"
)

type myPlugin struct{}

func (p *myPlugin) ListTools() []plugin.ToolSpec {
    return []plugin.ToolSpec{{
        Name:        "create_ticket",
        Description: "Create a support ticket",
        Parameters: json.RawMessage(`{
            "type": "object",
            "properties": {
                "title": {"type": "string", "description": "Ticket title"},
                "priority": {"type": "string", "enum": ["low", "medium", "high"]}
            },
            "required": ["title"]
        }`),
    }}
}

func (p *myPlugin) Execute(toolName string, input json.RawMessage, ctx plugin.Context) (*plugin.Result, error) {
    var args struct {
        Title    string `json:"title"`
        Priority string `json:"priority"`
    }
    _ = json.Unmarshal(input, &args)
    return &plugin.Result{
        Content: fmt.Sprintf("Created ticket: %s (priority: %s)", args.Title, args.Priority),
    }, nil
}

func (p *myPlugin) Shutdown() {}

func main() {
    plugin.Serve(&myPlugin{})
}

4. Build and install

go build -o my-plugin .
ggcode plugin install ticket-tools $(pwd)/my-plugin

SDK Reference

ToolSpec

Field Type Description
Name string Unique tool identifier
Description string Description shown to the LLM
Parameters json.RawMessage JSON Schema for tool parameters
Categories []string Optional grouping tags

Context

Field Type Description
WorkingDir string Agent's current working directory
SessionID string Current session identifier
Extra map[string]string Additional context values

Result

Field Type Description
Content string Text result returned to the LLM
IsError bool If true, treated as an error
Images []ResultImage Images in the result
SuggestedWorkingDir string Optional hint to change working directory

Non-Go Plugins

Any language with gRPC support works. The plugin must:

  1. Check the environment variable GGCODE_PLUGIN equals ggcode-grpc-plugin-v1
  2. Create a Unix domain socket
  3. Print the go-plugin handshake line to stdout:
    1|1|unix|/tmp/plugin-XXXXX|grpc|
    
    Format: core_version|app_version|network|socket_path|protocol|cert
  4. Start a gRPC server on that socket
  5. Register a health check service (go-plugin requires it)
  6. Implement ToolService with ListTools, Execute, Shutdown methods

See the Python and Node.js demos for complete implementations.

Protocol Details

Security

  • Plugins run with the same user permissions as ggcode
  • The host's permission system (tool_permissions) applies to plugin tools
  • Plugins do not have access to the host's API keys or config
  • Only working_dir and session_id are passed in the execution context

Limitations

  • One plugin process per config entry
  • Plugin startup adds to ggcode launch time (~200ms per plugin)
  • No hot-reload (restart ggcode to pick up changes)