glue
Open source · Go · MIT

Agent = Provider + Loop + Tools. In Go.

glue is a small, provider-agnostic agent harness — and the reference agents built on it. A reusable loop, typed tools, four model providers, opt-in persistence and search, all behind a small code-first API.

go get github.com/erain/glue
Codex · Gemini · NVIDIA build · OpenRouter · MCP · sqlite + FTS5 · local daemon
01 What it is

An agent loop, code-first, in Go.

Most agent frameworks bundle a model, a chain DSL, a deploy target, and a runtime opinion. glue separates concerns: a reusable provider-agnostic loop, a small Agent / Session API, four pluggable providers, and ready-to-register tool bundles. The whole framework fits in your head.

Inspired by pi-mono and flue: same conceptual shape, in Go. Single static binary, no runtime, no Python/Node version manager, no Docker just to run an agent.

The architectural rule (ADR-0005): every product concern enters glue only as an interface the host fills in. Sandboxing, channels, scheduling, permission policy — your code, not glue’s. That’s how the core stays small while real agents grow on top of it.

02 A minimal agent

Provider, session, prompt.

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/erain/glue"
	"github.com/erain/glue/providers/gemini"
)

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

	agent := glue.NewAgent(glue.AgentOptions{
		Provider: gemini.New(gemini.Options{}), // reads GEMINI_API_KEY
		Model:    "gemini-2.5-flash",
	})

	session, err := agent.Session(ctx, "demo")
	if err != nil {
		log.Fatal(err)
	}

	result, err := session.Prompt(ctx, "Reply with the single word: glue.")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(result.Text)
}

The session keeps an in-memory transcript, so a second session.Prompt(...) continues the conversation. Pass AgentOptions.Store (e.g. stores/file or stores/sqlite) and transcripts survive across processes. Other providers — Codex, NVIDIA, OpenRouter — are one import away.

03 Concepts

Seven types, one loop.

Once these click, the rest is API surface:

  • Provider — a model backend that streams assistant events.
  • Agent — provider, model, tools, store, work dir, roles. Built with glue.NewAgent.
  • Session — a named conversation with its own transcript; driven with session.Prompt.
  • Tool — a function the model can call. Defined with glue.NewTool[Args].
  • Store — where transcripts persist (stores/file or stores/sqlite). Optional.
  • Skill / Role — Markdown-driven reusable instructions and named instruction profiles.
  • loop — the engine: stream → run tools → append results → repeat until the model stops.

Every session.Prompt runs the same flow:

prompt ─▶ provider streams events ─▶ text? emit deltas
                                  └─▶ tool calls? run tools, append, loop
                                  └─▶ stop ─▶ return final text
04 What's in the box

Batteries included, nothing welded shut.

Four providers + failover

Codex (ChatGPT subscription), Gemini, NVIDIA build, OpenRouter. A driver-style registry + glue.WithFailover.

Typed tools

glue.NewTool[Args] decodes JSON into your Go type before the executor runs; failures surface as ErrorResult, not panics.

Subagents

glue.SubagentTool wraps a child Agent as a tool — fresh, isolated transcripts for delegated work.

Persistence + FTS5 search

stores/file for the simple default; stores/sqlite for cross-session recall via pure-Go FTS5.

Streaming

WithStreamWriter, WithToolLogger, Session.Subscribe — compose additively, never crowd each other out.

Skills & roles

AGENTS.md, .agents/skills/<name>/SKILL.md, and roles/*.md discovered from your WorkDir. Frontmatter sets model overrides.

Coding-agent bundle

read_file, write_file, edit_file, list_dir, find_files, grep, shell_exec, git_diff_branch — permission-gated where it matters.

MCP client

Consume Model Context Protocol servers (stdio / Streamable HTTP) as permission-gated glue.Tool values.

Local daemon + channels

glue serve / glue connect over HTTP+SSE. Telegram and other channels plug in as adapters in your agent package.

Each capability is opt-in. The core glue package doesn’t import any provider, store, or tool by default — adding them is an explicit import in your main.go.

05 Build your own

From minimal to packaged, in one guide.

The end-to-end guide walks you from a 15-line minimal agent to a packaged, tested CLI in ten steps: typed tools, persistence, streaming, project context, subagents, structured output, multi-provider failover, packaging, and testing with a fake provider.

Agents that ship a binary share six standard flags (--provider, --model, --id, --store, --work, --max-turns):

import (
	"flag"
	"github.com/erain/glue/cli"
)

fs := flag.NewFlagSet("my-agent", flag.ContinueOnError)
get := cli.RegisterStandardFlags(fs, nil)
_ = fs.Parse(os.Args[1:])

cfg := get() // cfg.Provider, cfg.Model, cfg.ID, cfg.Store, cfg.Work, cfg.MaxTurns
06 Built on glue

Two reference agents, in real use.

glue-review

A free, local pre-push branch reviewer. Reads the diff against main, deep-reads files when needed, and posts one sticky GitHub comment per PR — a short headline, severity bullets, and a fenced ```markdown fix block downstream coding agents (Claude Code, Codex, Cursor, Aider, …) paste in one step. Runs as a CLI or a GitHub Action.

glue-review.vercel.app · GitHub

peggy

A long-running personal-assistant agent: CLI, Telegram, and a shared HTTP+SSE daemon; durable sqlite+FTS5 memory with curated recall; opt-in local coding tools; MCP servers; scheduled/proactive runs; per-channel permission tiers. The best reference for a feature-rich agent built on glue.

GitHub · Tracker #110

07 Status

Pre-1.0, in active use.

The harness is feature-complete for the 0.x series and powers the two reference agents above. The public Agent / Session / Tool surface is stable in practice; minor versions may still break API until 1.0.0. See CHANGELOG.md.

GitHub · Guide · Design · ADRs · Tracker · Changelog · Contributing

08 FAQ

Anticipated questions.

How is glue different from flue?

Same conceptual shape — pi-mono-style reusable loop, small core, real agents on top — but Go instead of TypeScript, local-first (no platform fees), and shipped with reference agents that exercise the long-running primitives (memory, channels, scheduling, permissions) rather than just demoing the loop.

How is it different from langchaingo or other Go agent libraries?

glue is smaller and more opinionated. The whole framework fits in your head: provider, loop, session, tool. There’s no chain DSL, no graph compiler, no hidden global state. Trade-off: you write a little more glue (sorry) for the orchestration you want, in plain Go.

Why Go?

Single static binary. No runtime, no version managers, no Docker just to run an agent. Deploys to anything that takes a binary. Goroutines map cleanly to streaming + tool execution.

Is the Codex provider really supported?

It uses your ChatGPT-subscription auth via codex login, not an OpenAI API key. Subscription-auth via third-party tools is not formally documented by OpenAI; the provider is intended for personal use. Other providers (Gemini, NVIDIA, OpenRouter) use standard API keys.

API stability?

Pre-1.0. The public Agent / Session / Tool surface is stable in practice — it has survived ~30 PRs without breaking changes — but we reserve the right to break API on minor bumps until 1.0.0. See CHANGELOG.md.

Do I need an API key?

Yes for the network providers (GEMINI_API_KEY, NVIDIA_API_KEY, OPENROUTER_API_KEY). The Codex provider uses codex login. The openrouter/free meta-route can run free.