acp

A Go client for the Agent Client Protocol, versions 1 and 2. Start a coding agent, open a session, send prompts and read typed updates.

tuios.dev/acp is a Go client for the Agent Client Protocol (ACP). An editor or a terminal uses the protocol to drive a coding agent: it starts the agent, opens a session, sends prompts and reads what the agent does as typed updates. The messages are JSON-RPC 2.0, one per line, on the agent's stdin and stdout. tuios uses this package for its protocol panes (tuios start-agent --protocol acp).

go get tuios.dev/acp

The package uses only the standard library and needs Go 1.25 or later. The API reference is on pkg.go.dev.

What is in it

  • The JSON-RPC peer. Conn sends and receives requests in both directions, and handles $/cancel_request.
  • Version negotiation. Connect asks for a version. An agent asked for version 2 may answer 1. An agent that refuses 2 is started again through the transport and asked for 1. When no version fits, the error names the versions of both sides.
  • Sessions. New, resume, list, prompt, cancel and close.
  • Updates. Every session/update kind is a Go type, in one model for both versions. An unknown kind arrives as *UnknownUpdate with its raw JSON.
  • Permission requests. Answer with Choose or Cancel. The agent can withdraw a request with $/cancel_request.
  • Transports. Process starts the agent and talks over stdio. Pipe works over a pair of streams.

Run one prompt

package main

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

	"tuios.dev/acp"
)

func main() {
	ctx := context.Background()
	agent := &acp.Process{Path: "opencode", Args: []string{"acp"}, Stderr: os.Stderr}
	c, err := acp.Connect(ctx, agent, acp.ClientOptions{
		Info: acp.Implementation{Name: "example", Version: "0.1.0"},
		OnUpdate: func(u acp.Update) {
			if m, ok := u.(*acp.MessageUpdate); ok && m.Role == acp.RoleAgent && m.Op == acp.MessageAppend {
				fmt.Print(m.Text())
			}
		},
		// Dismiss every permission request: the agent does nothing it
		// has to ask for.
		OnPermission: func(p *acp.PermissionRequest) { p.Cancel() },
	})
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	cwd, _ := os.Getwd()
	s, err := c.NewSession(ctx, cwd)
	if err != nil {
		log.Fatal(err)
	}
	end, err := s.Prompt(ctx, acp.Text("Summarise the TODO comments in this folder."))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("\nstopped:", end.Reason)
}

OnUpdate and OnPermission run on the read goroutine of the connection, in the order the agent sent the messages. They must not block. Answer a permission request from any goroutine.

The package passes the text of the agent through as it came. The text can hold terminal escape sequences. A program that draws it in a terminal must remove them first.

Versions of the protocol

VersionStatus in the specIn this package
1stablespoken, the default
2draftspoken when ClientOptions.MaxVersion is 2

The spec asks clients not to ask for version 2 by default while it is a draft, so DefaultVersion is 1 and LatestVersion is 2. Set MaxVersion: 2 in the options to ask for version 2 first. The version 2 schema can still change. This package follows the draft of 2026-11-13.

Updates follow the version 2 model, which can say more. A version 1 update arrives as the same type, with the fields that version 1 cannot state left at their zero value. In version 2 the answer to a prompt only says that the agent took the prompt. Session.Prompt waits for the state_update to idle that ends the turn, so it returns at the end of the turn in both versions.

The client offers the agent no file system and no terminal, so a conforming agent does its own reads, writes and commands. The agent side of the protocol is not in the package.

API overview

NameDoes
Connect, ClientOptionsStart a connection and negotiate the version.
Process, PipeThe transports.
ConnThe JSON-RPC peer.
SessionNew, resume, list, prompt, cancel and close.
Update, UnknownUpdateWhat the agent reports during a turn.
PermissionRequestA question from the agent, answered with Choose or Cancel.

What stays in tuios

tuios keeps the pane program (agent-proto) and its transcript, the agent state and the Inbox reports, the keys that answer a permission, and the [agents] acp_version option. tuios does not use acp.Process. A protocol pane starts its agent through its own transport, so the agent gets no controlling terminal.

Versions

The module is at v0 and has no tag yet. The API can change between minor versions. Its tags will have the folder name as a prefix, such as acp/v0.1.0. The source is in the acp folder of the tuios repository, under the MIT licence.

tuios lives only at tuios.dev and github.com/Gaurav-Gosain/tuios. tuios has no X or Twitter account. An account that offers a tuios token or presale is not this project.

On this page