goat

module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 31, 2026 License: BSD-3-Clause

README ΒΆ

goat 🐐

Compile, ship, and extend tool-using AI agents in Go.

CI Go Reference BSD 3-Clause License

goatc Β· Features Β· SDK quick start Β· Packages Β· Documentation

goat combines an agent compiler, an asynchronous runtime, persistent conversation context, extensible tools, Milvus retrieval, multi-provider embeddings, structured prompt building, and typed streams in one Go module. Its first-class goatc compiler turns YAML plus provider-backed toolsβ€”local Go plugins, gRPC services, and MCP serversβ€”into a single distributable Agent executable with an interactive Bubble Tea UI. The agent layer is built on CloudWeGo Eino and accepts any model.AgenticModel implementation.

Features

  • Agent compiler (goatc) β€” combine local Go plugins, multiple gRPC tools, and multiple MCP servers through one provider-based YAML schema, then emit one interactive executable.
  • Built-in terminal UI β€” stream final answers, inspect tool execution in real time, continue conversations, steer active runs, cancel work, and monitor token usage.
  • Native tool calling β€” execute one or more model-selected tools in an agent loop.
  • Model agnostic β€” use Eino adapters for OpenAI, Azure OpenAI, Claude, Gemini, or another compatible provider.
  • Context management β€” choose RAM, local files, SQLite, or MySQL and resume a conversation by ContextUID.
  • Live steering β€” queue one or more user messages while an agent runs and apply them at the next protocol-safe turn boundary.
  • Context compression β€” compact long tool histories with precise, aggressive, or no-model discard strategies.
  • Extensible tools β€” register Go functions, MCP tools, Go shared libraries, or gRPC plugins.
  • Planning and skills β€” expose built-in planning tools and load skills on demand from a skills/ directory.
  • Streaming execution β€” consume typed tool and final-answer steps, token usage, callbacks, and final-answer webhooks.
  • Multimodal input and output β€” pass image URLs, Base64 data, or binary images through supported models and tools.
  • Milvus retrieval β€” use dense vector, BM25, or hybrid retrieval with filters, partitions, and JSON fields.
  • Reusable primitives β€” multi-provider embeddings, a fluent prompt builder, and concurrent generic streams.

goatc agent compiler

goatc is the shortest path from Go tools to a runnable Agent. Instead of writing model initialization, plugin loading, context management, streaming, and terminal UI glue by hand, describe the Agent in YAML and compile it:

Local Go tools + gRPC services + MCP servers + goatc.yaml
                         β”‚
                         β–Ό
                       goatc
                         β”‚
                         β”œβ”€β”€ builds local tools as native .so plugins
                         β”œβ”€β”€ configures remote tool providers
                         β”œβ”€β”€ embeds normalized YAML and local plugins
                         └── builds the Bubble Tea application
                         β”‚
                         β–Ό
                one distributable executable

What the generated executable includes

  • OpenAI, Claude/Anthropic, or Gemini model initialization driven by environment-based credentials.
  • Provider-based tools: compiled and embedded Go plugins, multiple goat gRPC tool services, and MCP servers over stdio, SSE, or Streamable HTTP.
  • RAM, file, or SQLite conversation persistence.
  • Planning, parallel tool execution, context compression, per-run skill directories, and special requirements.
  • A Bubble Tea interface with streamed answers, live tool status and results, multi-turn history, active-run steering, cancellation, and token accounting.

A minimal project looks like this:

my-agent/
β”œβ”€β”€ go.mod
β”œβ”€β”€ goatc.yaml
└── tools/
    β”œβ”€β”€ search/          # package main; exports New() toolplugin.ToolPlugin
    └── workspace/       # package main; exports New() toolplugin.ToolPlugin
version: v1

agent:
  name: research-agent
  model_max_tokens_k: 128
  max_steps: 12
  enable_planning: true
  parallel_tools: 3
  compress: true
  skills_dir: ./skills

model:
  provider: openai
  name: gpt-5
  api_key_env: OPENAI_API_KEY

context:
  backend: file
  path: data/conversations

tools:
  # Omit provider for a backward-compatible local Go plugin.
  - name: search
    source: ./tools/search
  - provider: go_plugin
    name: workspace
    source: ./tools/workspace

  # Add as many goat gRPC tool services as needed.
  - provider: grpc
    name: translator
    address: 127.0.0.1:50051
  - provider: grpc
    address: 127.0.0.1:50052

  # Each MCP server can expose multiple tools.
  - provider: mcp
    name: filesystem
    transport: stdio
    command: npx
    args: [-y, "@modelcontextprotocol/server-filesystem", /workspace]
  - provider: mcp
    transport: streamable_http
    url: https://mcp.example.com/mcp
    headers:
      Authorization: Bearer ${MCP_TOKEN}

build:
  output: ./dist/research-agent

tui:
  welcome: Ask me to research, analyze, or modify the workspace.

Install, validate, build, and run:

go install github.com/torrischen/goat/goatc@latest

goatc validate -f goatc.yaml
goatc build -f goatc.yaml

export OPENAI_API_KEY="your-api-key"
export MCP_TOKEN="your-mcp-token"
./dist/research-agent

The tools[].provider field is the common extension point. go_plugin compiles and embeds a local source directory, grpc imports a goat PluginService by address, and mcp initializes a stdio, SSE, or Streamable HTTP server and registers every tool it exposes. Add multiple entries of any provider type in one Agent. MCP values such as ${MCP_TOKEN} are resolved from the runtime environment, so secrets do not need to be embedded in YAML.

Each local source directory is one plugin build unit and follows the existing New() toolplugin.ToolPlugin contract. The Agent executable and its local plugins are built together with the same Go toolchain and build tags. The output is one delivery artifact; at startup it extracts embedded plugins to a temporary directory because Go's plugin.Open requires filesystem paths. Remote-only configurations build without embedded .so files. A configured skills_dir remains a runtime directory and is not embedded.

Go plugins are built natively and supported on Linux, macOS, and FreeBSD. See the complete goatc guide for provider configuration, tool contracts, keyboard controls, and build details.

Packages

Package Purpose
goatc YAML-driven Agent compiler with Go plugin, gRPC, and MCP tool providers plus a Bubble Tea interface.
agent/react Asynchronous native function-calling agent runtime.
agent/common Agent, tool, step, callback, and multimodal contracts.
agent/contextmgr Context manager interface plus RAM, file, SQLite, and MySQL backends.
agent/tools Planning, skills, terminal, and shell tools.
agent/toolplugin Go shared-library and gRPC tool plugins.
embedder Embedding clients for OpenAI-compatible APIs, Gemini, Cohere, Voyage AI, and Ollama.
retriever/milvus Vector, BM25, and hybrid Milvus retrievers.
prompt Fluent Markdown prompt builder.
streaming Concurrent, type-safe generic streams.
flowchart LR
    Source[YAML + Go Β· gRPC Β· MCP providers] --> Goatc[goatc compiler]
    Goatc --> Binary[Agent executable]
    Binary --> TUI[Bubble Tea TUI]
    Binary --> Agent[Agent runtime]
    SDK[Go SDK application] --> Agent
    Agent --> Model[Eino AgenticModel]
    Agent --> Tools[Go Β· MCP Β· gRPC Β· shared-library tools]
    Agent --> ContextManager[RAM Β· files Β· SQLite Β· MySQL]
    Agent --> Steps[Typed step stream]
    SDK --> Retriever[Retriever]
    Retriever --> Milvus[(Milvus)]
    Retriever --> Embedder[Embedder]

Requirements

  • Go 1.25.8 or newer.
  • Credentials for the model or embedding provider you choose.
  • Milvus 2.6 only when using the retriever packages.
  • CGO and a C compiler when using the SQLite context manager.
  • Linux, macOS, or FreeBSD for goatc shared-library builds; Agent and plugins are built natively for the current OS and architecture.

Installation

Install the Agent compiler from source:

go install github.com/torrischen/goat/goatc@latest

Prebuilt goatc archives for Linux, macOS, Windows, and FreeBSD (amd64 and arm64) are attached to every GitHub Release, together with SHA256SUMS.

When embedding goat as a library, install only the packages your application needs:

go get github.com/torrischen/goat/agent/react
go get github.com/torrischen/goat/agent/contextmgr/ram
go get github.com/cloudwego/eino-ext/components/model/agenticopenai

Optional components can be added independently:

go get github.com/torrischen/goat/retriever/milvus/hybrid
go get github.com/torrischen/goat/prompt
go get github.com/torrischen/goat/streaming

SDK quick start

Use this path when embedding goat directly into a Go application. For a YAML-driven, ready-to-run Agent executable, start with goatc.

Set an API key:

export OPENAI_API_KEY="your-api-key"

Create and run an agent:

package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"os"

	"github.com/cloudwego/eino-ext/components/model/agenticopenai"
	"github.com/torrischen/goat/agent/common"
	"github.com/torrischen/goat/agent/contextmgr/ram"
	"github.com/torrischen/goat/agent/react"
	"github.com/torrischen/goat/streaming"
)

func main() {
	ctx := context.Background()

	llm, err := agenticopenai.NewResponsesModel(ctx, &agenticopenai.ResponsesConfig{
		APIKey: os.Getenv("OPENAI_API_KEY"),
		Model:  "gpt-5.2",
	})
	if err != nil {
		log.Fatal(err)
	}

	// 128 means an approximately 128K-token model context window.
	agent := react.NewAgent(llm, 128, ram.NewRAMContextManager())

	contextUID, steps, err := agent.Do(ctx, &common.AgentDoArgs{
		UserInput: common.AgentUserInput{
			Text: "Explain why typed streams are useful in Go in three bullets.",
		},
		MaxStep: 8,
	})
	if err != nil {
		log.Fatal(err)
	}

	for {
		step, err := steps.ReadWithContext(ctx)
		switch {
		case errors.Is(err, streaming.ErrStreamClosed):
			fmt.Printf("\nConversation: %s\n", contextUID)
			return
		case err != nil:
			log.Fatal(err)
		case step.IsFinalAnswer:
			fmt.Println(step.Observation)
		}
	}
}

Agent.Do stores the user message, starts the agent loop in the background, and immediately returns a ContextUID plus a stream for that run. Consume the stream until streaming.ErrStreamClosed before starting another turn with the same ContextUID.

While the run is active, queue additional user messages with Steer:

err = agent.Steer(ctx, &common.AgentSteerArgs{
	ContextUID: contextUID,
	UserInputs: []common.AgentUserInput{
		{Text: "Do not deploy yet."},
		{Text: "Run all tests first."},
	},
})

The messages are queued in the context manager and applied after the next complete tool turn. A final answer always wins and discards messages that are still pending at that boundary. After final commit, Steer returns contextmgr.ErrConversationFinalized; the next Do user input reopens steering.

Add a custom tool

Tools use JSON Schema parameters and return text or multimodal results:

weatherTool := common.NewDefaultTool(
	"get_weather",
	"Return the current weather for a city.",
	common.NewToolParameters(common.ToolProperty{
		Name:        "city",
		Type:        "string",
		Required:    true,
		Description: "City name, for example Tokyo.",
	}),
	func(_ *common.AgentContext, input map[string]any) common.ToolResult {
		city, ok := input["city"].(string)
		if !ok || city == "" {
			return common.NewDefaultToolResult("city must be a non-empty string")
		}
		return common.NewDefaultToolResult(
			fmt.Sprintf("The weather in %s is clear and 22Β°C.", city),
		)
	},
)

agent.AddTool(ctx, weatherTool)

Use ToolProperty.Items and ToolProperty.Properties for array and nested-object schemas. Tool names are normalized for model compatibility, and duplicate names receive a numeric suffix.

Enable planning, compression, and parallel tools

_, planningSteps, err := agent.Do(ctx, &common.AgentDoArgs{
	UserInput:      common.AgentUserInput{Text: "Analyze this project and propose a refactor."},
	MaxStep:        12,
	EnablePlanning: true,
	Compress:       true,
	CompressionOptions: common.CompressionOptions{
		Strategy:       common.CompressionStrategyPrecise,
		RecentMessages: 12,
	},
	ToolExecutionOptions: &common.ToolExecutionOptions{
		EnableParallel: true,
		MaxConcurrency: 4,
	},
})

Consume planningSteps in the same way as the quick-start stream; the run is complete when the stream closes.

Conversation context management

Pass a contextmgr.ContextManager implementation to react.NewAgent. Passing nil uses a file.FileContextManager rooted at data/conversations.

Backend Constructor Best suited for
RAM ram.NewRAMContextManager() Tests and short-lived processes.
Files file.NewFileContextManager("") Simple local atomic-file persistence.
SQLite sqlite.NewSQLiteContextManager("") Durable single-node applications.
MySQL mysql.NewMysqlContextManager(...) Shared, multi-process deployments.

Continue a completed conversation by passing the returned ID into the next run:

_, nextSteps, err := agent.Do(ctx, &common.AgentDoArgs{
	ContextUID: contextUID,
	UserInput: common.AgentUserInput{Text: "Summarize our conversation."},
})

Retrieval

The Milvus integration exposes three retrieval strategies behind similar collection, partition, write, search, upsert, and delete APIs:

Retriever Search Embedder required
vector Dense semantic similarity Yes
bm25 Keyword/full-text relevance No
hybrid Vector + BM25 with RRF or weighted reranking Yes

Retrievers support scalar and JSON-path filters, custom JSON fields and indexes, pagination, and partition management. See the Retriever guide for a complete hybrid-search example and operational notes.

Model providers

react.NewAgent accepts Eino's model.AgenticModel interface. Provider authentication, endpoints, and provider-specific options stay in the selected Eino adapter:

  • agenticopenai for OpenAI Responses and Azure OpenAI.
  • agenticclaude for Claude.
  • agenticgemini for Gemini and Vertex AI.

See the Agent SDK guide for provider setup, MCP registration, skills, multimodal messages, callbacks, webhooks, and plugin loading.

Documentation

Security

Model-generated tool arguments are untrusted input. Validate parameters, enforce authorization and idempotency for side effects, apply timeouts, and run privileged tools in a sandbox. In particular, agent/tools.Terminal and agent/tools.ShellCommand execute commands with the permissions of the current process and should only be registered in controlled environments.

Never commit provider credentials or include them directly in tool output, logs, or persisted conversation context.

Development

git clone https://github.com/torrischen/goat.git
cd goat
go mod download
go test ./...

When changing the gRPC plugin protocol, regenerate its Go bindings with:

make proto

Issues and pull requests are welcome. Please format Go changes with gofmt and include tests for new behavior. See the contribution guide, security policy, code of conduct, and changelog for project policies.

License

goat is distributed under the BSD 3-Clause License.

Directories ΒΆ

Path Synopsis
agent
contextmgr
Package contextmgr defines conversation context management.
Package contextmgr defines conversation context management.
react/compression
Package compression provides context-compression strategies for the React agent.
Package compression provides context-compression strategies for the React agent.
cohere
Package cohere implements embeddings using Cohere's Embed API v2.
Package cohere implements embeddings using Cohere's Embed API v2.
gemini
Package gemini implements embeddings using the Gemini batchEmbedContents API.
Package gemini implements embeddings using the Gemini batchEmbedContents API.
ollama
Package ollama implements embeddings using Ollama's local HTTP API.
Package ollama implements embeddings using Ollama's local HTTP API.
voyage
Package voyage implements embeddings using the Voyage AI API.
Package voyage implements embeddings using the Voyage AI API.
complex_agent command
Command complex_agent demonstrates a multi-step OpenAI agent with planning, parallel tool execution, run-scoped metadata, callbacks, context compression, final-answer streaming, and token accounting.
Command complex_agent demonstrates a multi-step OpenAI agent with planning, parallel tool execution, run-scoped metadata, callbacks, context compression, final-answer streaming, and token accounting.
Command goatc compiles Go tool plugins and assembles them into a standalone interactive goat agent binary.
Command goatc compiles Go tool plugins and assembles them into a standalone interactive goat agent binary.
compiler
Package compiler implements the goatc build pipeline.
Package compiler implements the goatc build pipeline.
config
Package config defines the goatc build and runtime configuration.
Package config defines the goatc build and runtime configuration.
runtime
Package runtime starts an agent assembled by goatc.
Package runtime starts an agent assembled by goatc.
tui
Package tui provides the interactive terminal UI used by generated agents.
Package tui provides the interactive terminal UI used by generated agents.
Package prompt provides a fluent builder for composing structured prompts.
Package prompt provides a fluent builder for composing structured prompts.
retriever

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL