Model or dataset
trpc-group/trpc-agent-go avatar
trpc-group/trpc-agent-go

tRPC-Agent-Go: a Go agent framework for services that already run Go

A Go framework for building production agent systems with graph workflows, tools, memory, A2A, AG-UI, MCP, evaluation, and observability.

1,823 stars315 forksGoApache-2.0

At a glance

What is it?
tRPC-Agent-Go bundles agents, graph workflows, tools, memory and OpenTelemetry into one Go module. It fits teams whose agents have to live inside an existing Go service, and it costs more wiring than a Python notebook.
Who is it for?
Adopt tRPC-Agent-Go if your agents must run inside an existing Go service and you want graph workflows, tool calling, session memory and OpenTelemetry in one module rather than a Python sidecar. Skip it if you are prototyping in notebooks or need a hosted runtime that manages deployment for you.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The Go service that needs an agent loop, not a second runtime

Most agent frameworks assume Python and assume the agent is the application. tRPC-Agent-Go assumes the opposite. It is a Go module, trpc.group/trpc-go/trpc-agent-go, published under Apache-2.0, and the README frames it as a way to build agent applications that "fit Go services: concurrent, observable, easy to deploy". That sentence is the whole pitch. If your request path already runs through Go, adding an agent should not mean standing up a Python process, a queue between the two, and a second set of tracing conventions.

The intended users are backend and platform engineers. The README lists customer support bots, data analysis assistants, DevOps automation, business process automation, and RAG knowledge management as the cases it is built for. What those have in common is that they are services with latency budgets, cancellation semantics and an existing observability stack, not one-off scripts. The repository layout backs this up: runner/, server/, session/, storage/, telemetry/ and plugin/ sit alongside the agent packages, which is the shape of a library you embed rather than a CLI you run.

GraphAgent, runners and the state that survives a turn

The core abstraction is the agent, and the runner that drives it. runner.NewRunner("app", agent) wraps an agent with an application name, and runner.Run(ctx, "user-1", "session-1", model.NewUserMessage("Hello")) takes a context, a user identifier, a session identifier and a message. Context cancellation is called out as a first-class feature, which matters because a Go service that cannot cancel an in-flight LLM call cannot meet a deadline.

Above single agents sits GraphAgent, described in the README as type-safe graph workflows with multi-conditional routing and "functionally equivalent to LangGraph for Go". That equivalence claim is the project's own, and it is the right frame: you get a directed graph of steps, branching on conditions, rather than a free-form loop. For orchestration there are chain and parallel agents, shown in the README as:

go
// Chain agents for complex workflows
pipeline := chainagent.New("pipeline",
    chainagent.WithSubAgents([]agent.Agent{
        analyzer, processor, reporter,
    }))

// Or run them in parallel
parallel := parallelagent.New("concurrent",
    parallelagent.WithSubAgents(tasks))

The repository also contains a team/ package and cycle-based workflows are named in the feature list, so the graph model is not limited to acyclic pipelines.

State is split into layers. Sessions cover a conversation. Memory is a service, created with memorysvc.NewInMemoryService() and attached at runner level through runner.WithMemoryService(memory), with the README noting that agents then "remember context across sessions". Artifacts and knowledge retrieval are separate packages. The design choice worth noticing is that memory is attached to the runner, not to the agent, so swapping an in-memory store for a persistent one is a runner-level change.

Installing tRPC-Agent-Go and getting one agent to answer

The module path is trpc.group/trpc-go/trpc-agent-go and go.mod declares go 1.21, so that is the floor for your toolchain. The README's Quick Start section documents prerequisites, a runnable example, basic usage and how to stop a run, and the README points readers at pkg.go.dev for the package reference. It does not document a version pin beyond the module path, so check the releases page for the current tag before you pin one.

Once the module is in your go.mod, the README's basic usage example looks like this, with the memory service attached at runner level rather than to the agent:

go
// Persistent memory with search
memory := memorysvc.NewInMemoryService()
agent := llmagent.New("assistant",
    llmagent.WithTools(memory.Tools()),
    llmagent.WithModel(model))

// Memory service managed at runner level
runner := runner.NewRunner("app", agent,
    runner.WithMemoryService(memory))

// Agents remember context across sessions

What you should see is a stream of events on the returned channel rather than a single string. That is deliberate: streaming runners are listed as a reason to pick the framework, and the event package exists to carry them. Note that model and ctx are not defined in the README snippet; you supply a model implementation and a context with whatever cancellation deadline your service already uses.

To stop a run, the README devotes a subsection to it, and examples/cancelrun/ exists in the repository. The mechanism is context cancellation, which is the idiomatic Go answer rather than a framework-specific Stop call.

Skills, self-evolution and the footguns in the skill tooling

Skills are folders containing a SKILL.md specification, loaded through skill.NewFSRepository("./skills") and exposed to an agent as two tools:

go
// Skills are folders with a SKILL.md spec.
repo, _ := skill.NewFSRepository("./skills")

// Let the agent load and run skills on demand.
tools := []tool.Tool{
    skilltool.NewLoadTool(repo),
    skilltool.NewRunTool(repo, localexec.New()),
}

The load tool lets the model pull a skill into context on demand; the run tool executes it. This is a reasonable design, and the README is unusually candid about the sharp edges.

Three of them are worth repeating. First, NewFSRepository accepts an HTTP(S) URL pointing at a .zip or .tar.gz archive, which is downloaded and cached locally, with SKILLS_CACHE_DIR overriding the cache location. Second, it accepts multiple roots, which the README suggests for combining shared skills with user-private ones. Third, and this is the one that will bite people, if you wire Skills through LLMAgent with llmagent.WithCodeExecutor(...), the README advises considering llmagent.WithEnableCodeExecutionResponseProcessor(false) so that Markdown fenced code blocks embedded in assistant text do not auto-execute while skill_run is enabled. An agent that writes a code block in its prose and has that block executed is a real failure mode, and the framework's default response processor is what creates it.

There is also a lifecycle constraint: in a long-lived process you must call repo.Refresh() after installing, deleting or renaming a skill, or the next turn will not see the change. That is fine for a service that restarts often and easy to forget in one that does not.

Self-evolution sits on top of the same directory:

go
repo, _ := skill.NewFSRepository("./managed_skills")
evo := evolution.NewService(reviewerModel,
    evolution.WithManagedSkillsDir("./managed_skills"),
    evolution.WithSkillRepository(repo))
defer evo.Close()

runner := runner.NewRunner("app", agent,
    runner.WithEvolutionService(evo))

Completed sessions are reviewed asynchronously, passed through quality gates, and published back as managed skills for future turns. The README does not describe what the quality gates measure or how to tune them, which is the weakest documented area of the project.

MCP, A2A and AG-UI: three protocols, three different jobs

The framework speaks three protocols, and conflating them is a common mistake. MCP is for tools: mcptool.New(serverConn) wraps an MCP server connection as a tool, and go.mod depends on trpc.group/trpc-go/trpc-mcp-go. A2A is for agent-to-agent interoperability, and go.mod depends on trpc.group/trpc-go/trpc-a2a-go; the examples directory contains a2aadk, a2aagent, a2acodeexecution, a2amultipath and a2asubagent, which suggests the integration is exercised from several directions. AG-UI is for frontends, with examples/agui/ in the tree.

For a Go team, the practical value is that these arrive as packages in the same module rather than as sidecars. The cost is dependency weight. go.mod pulls in the OpenTelemetry SDK and OTLP exporters over both gRPC and HTTP, gRPC and protobuf, zap, sqlite3 via mattn/go-sqlite3, the OpenAI Go client, and a handful of document and text libraries including goldmark, gse and two DOCX packages. If your service is small, that is a lot of transitive surface for an agent feature. Note also that mattn/go-sqlite3 requires cgo unless you replace it, which is a constraint the README does not discuss.

Where the documentation goes quiet

Observability is the best-specified part of the README and also the most provider-specific. The example starts Langfuse and attaches span attributes to a run:

go
// Start Langfuse integration
clean, _ := langfuse.Start(ctx)
defer clean(ctx)

runner := runner.NewRunner("app", agent)
// Run with Langfuse attributes
events, _ := runner.Run(ctx, "user-1", "session-1",
    model.NewUserMessage("Hello"),
    agent.WithSpanAttributes(
        attribute.String("langfuse.user.id", "user-1"),
        attribute.String("langfuse.session.id", "session-1"),
    ))

Those attribute keys are Langfuse's, not a neutral convention, so if your tracing backend is not Langfuse you are reading the OpenTelemetry packages directly. The README mentions Langfuse examples specifically and does not document a generic exporter configuration.

Evaluation is thinner still. evaluation.New("app", runner, evaluation.WithNumRuns(3)) followed by evaluator.Evaluate(ctx, "math-basic") returns a result with an OverallStatus field. Where eval sets are defined, what metrics exist beyond that status, and how to write a custom metric are not covered in the README. The benchmark directory exists at the repository root, so there is more to find, but the README does not point at it.

The prompt caching claim deserves the same caution. The feature list says "Automatic cost optimization with 90% savings on cached content". That is a statement about cached content, not about your bill, and the README does not explain which providers support it or how to verify it is working. Treat it as a capability to confirm rather than a number to plan around.

Choosing between tRPC-Agent-Go and LangGraph

The comparison the README invites is LangGraph, by claiming GraphAgent is "functionally equivalent to LangGraph for Go". The real difference is not the graph model, which is similar: nodes, conditional edges, shared state. It is the runtime and the ecosystem. LangGraph is Python, sits in the same process as the rest of the Python ML stack, and has a large body of examples and integrations written against it. tRPC-Agent-Go is Go, compiles to a single binary, and inherits Go's concurrency and deployment story at the cost of a smaller ecosystem and no access to Python-only tooling.

The decision usually comes down to where the rest of the system lives. If your retrieval, your model calls and your business logic are already Python, adding a Go agent means a language boundary and an RPC hop. If they are already Go, the reverse is true. There is a third option worth naming: writing the loop yourself against a model SDK. For a single agent with two tools, that is perhaps a few hundred lines, and it avoids the dependency weight listed above. tRPC-Agent-Go earns its place when you need the graph, the session and memory layers, the protocol integrations, and the tracing, and you would otherwise be rebuilding them.

Maintenance, licensing and what an upgrade costs

The repository is not archived, and the last push was on 2026-08-20. Releases have been frequent: v1.11.0 on 2026-08-06, v1.11.1 on 2026-08-13, v1.11.2 on 2026-08-20. Three minor releases in two weeks is a fast cadence, which cuts both ways. You get fixes quickly; you also get a moving target, and a framework at v1.11 with this release rhythm is not one to pin loosely in a production service.

The licence is Apache-2.0, which is permissive and includes an explicit patent grant. Two files are worth noting: the repository contains both LICENSE and LICENSE.original, and a NOTICE file. If you redistribute the framework, Apache-2.0 section 4 requires you to carry the NOTICE contents with your distribution. That is a packaging step, not a legal question, and it is the kind of thing that gets missed when a dependency arrives transitively. For anything beyond that, read the licence text itself rather than a summary.

Upgrade cost is dominated by the transitive dependency set. Because go.mod pins gRPC, protobuf, the OpenTelemetry SDK and the tRPC A2A and MCP modules, a minor bump here can move several of those. Run go mod graph or go mod why against the module before upgrading in a service that has its own pins on gRPC or OpenTelemetry, and budget for the diff rather than assuming a patch release is inert.

Editorial conclusion

Adopt tRPC-Agent-Go if your agents must run inside an existing Go service and you want graph workflows, tool calling, session memory and OpenTelemetry in one module rather than a Python sidecar. Skip it if you are prototyping in notebooks or need a hosted runtime that manages deployment for you. Before committing, verify two things against your own build: that your toolchain satisfies the go 1.21 directive in go.mod, and that your model provider is one the model package actually wires up, since the README does not list supported providers.

Frequently asked questions

What are the 5 types of agent in AI?

The README does not classify agents into types. It describes the agent categories the framework provides: single LLM agents, chain agents, parallel agents and GraphAgent workflows, plus multi-agent collaboration patterns.

What does an agent browser do?

The README does not describe a browser agent. It lists web search as one of the tools in the ecosystem, alongside function tools, MCP tools, code execution and custom services.

What are three types of agents?

The README does not enumerate three types of agents. It names the orchestration patterns it supports, including chain, parallel and cycle-based workflows, and describes GraphAgent as a type-safe graph workflow with multi-conditional routing.

What does "computer use agent" mean?

The README does not use that term. Its closest feature is code execution, exposed through llmagent.WithCodeExecutor(...) and the codeexecutor package, which the README discusses alongside a warning about auto-executing fenced code blocks.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/trpc-group-trpc-agent-go.svg)](https://hysenlabs.com/projects/trpc-group-trpc-agent-go)