cotty

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 26, 2026 License: CC0-1.0 Imports: 26 Imported by: 0

README

cotty

CI codecov

cotty shares a terminal session between you and an AI agent.

You start a command such as ssh or a serial console under cotty wrap and use it as usual. The agent reads the same output and types into the same session through an MCP server, cotty mcp. Both of you can type at any time, and you can deny the agent's input with a key.

[your terminal]                          [agent, e.g. Claude Code]
 cotty wrap -n web1 ssh web1                    | stdio
   runs ssh in a pty                          cotty mcp
   listens on ~/.cotty/sock/web1.sock <-------'

Installation

go install github.com/winebarrel/cotty/cmd/cotty@latest

Or download a binary from the releases.

Agent setup

The agent needs the MCP server, cotty mcp, and preferably the cotty skill, which tells it how to work in a session: waiting for prompts, avoiding full-screen programs, asking before changing anything, and never typing passwords.

For Claude Code, install the plugin. It registers the MCP server and adds the skill:

claude plugin marketplace add winebarrel/cotty
claude plugin install cotty@cotty

For other agents, install the skill with skills and register the MCP server with the agent. For Codex:

npx skills add winebarrel/cotty -a codex
codex mcp add cotty -- cotty mcp

For any other MCP client, the server is the command cotty with the argument mcp.

Usage

Start a session with a name:

cotty wrap -n web1 ssh web1.example.com
cotty wrap -n board picocom -b 115200 /dev/tty.usbserial-0001

Then ask the agent to work in the session, for example "check the disk usage on web1".

Flags of cotty wrap go before the command; everything from the command on is passed to it as is.

Options
Flag Environment variable Default Description
--home COTTY_HOME ~/.cotty Directory for session sockets and logs.
wrap --buffer-size COTTY_BUFFER_SIZE 1MiB How much recent output to keep for the agent to read.
mcp --read-max COTTY_READ_MAX 32KiB Most output one read returns. Older output beyond it is dropped.
mcp --tail-lines COTTY_TAIL_LINES 50 Lines a read returns when it has no previous read to continue from.
mcp --timeout COTTY_TIMEOUT 30s How long a read waits when the agent does not say.
mcp --max-timeout COTTY_MAX_TIMEOUT 10m Longest wait the agent may ask a read for.

Sizes take a unit of B, K, KB, KiB, M, MB or MiB, all powers of 1024. To change the mcp options, set the environment variables for the agent, or pass the flags when you register the server yourself:

codex mcp add cotty -- cotty mcp --read-max 64KiB --max-timeout 30m
Usage: cotty <command> [flags]

Share a terminal session with an AI agent.

Flags:
  -h, --help               Show context-sensitive help.
      --version
      --home="~/.cotty"    Directory for session sockets and logs ($COTTY_HOME).

Commands:
  wrap --name=STRING <command> ... [flags]
    Run a command in a terminal shared with the agent.

  mcp [flags]
    Serve the sessions to an agent over MCP on stdio.
Key bindings
Keys Action
Ctrl-] a Allow or deny the agent's input (allowed at start)
Ctrl-] ? Show help
Ctrl-] Ctrl-] Send Ctrl-] to the command
MCP tools
Tool Description
list_sessions List the running sessions.
send Type text into a session, followed by Enter unless enter is false.
send_key Press a special key such as ctrl-c, up or tab.
read Read the output that arrived since the previous read, as plain text. wait_for waits for a regular expression, idle_ms waits for the output to settle, and tail_lines returns the last lines instead.

To confirm each input while letting the agent read freely, allow only the read-only tools in Claude Code's permissions. With the plugin, the tools are named as follows:

{
  "permissions": {
    "allow": ["mcp__plugin_cotty_cotty__list_sessions", "mcp__plugin_cotty_cotty__read"]
  }
}
Files
  • ~/.cotty/sock/<name>.sock: the session socket, removed when the session ends. Only you can connect to it.
  • ~/.cotty/log/<name>-<YYYYMMDD-HHMMSS>.log: the session output as plain text, with escape sequences removed.

The command runs with COTTY_SESSION=<name> in its environment.

Notes

  • The agent sees the output from the start of the session, up to --buffer-size. The log keeps all of it.
  • Passwords you type at a prompt that turns echo off, as ssh and sudo do, never appear in the output, so the agent does not see them.

Documentation

Overview

Package cotty shares a terminal session between a person and an AI agent.

The person starts a program under `cotty wrap` and uses it as usual. The wrapper listens on a Unix socket, through which `cotty mcp` lets the agent read the program's output and type into it. There is no daemon: each wrapper owns its session, and the socket directory is the list of sessions.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ByteSize

type ByteSize int

ByteSize is a positive number of bytes, written as a number with an optional unit: B, K, KB, KiB, M, MB or MiB. Every unit is a power of 1024.

func (*ByteSize) UnmarshalText

func (b *ByteSize) UnmarshalText(text []byte) error

type Context

type Context struct {
	// Home is the directory holding the sockets and logs.
	Home      string
	Version   string
	Stdin     *os.File
	Stdout    io.Writer
	ErrOutput io.Writer
}

Context carries what commands need from the process they run in.

type ExitError

type ExitError struct {
	Code int
}

ExitError reports the exit status of the wrapped command, which cotty exits with in turn.

func (*ExitError) Error

func (e *ExitError) Error() string

type MCPCmd

type MCPCmd struct {
	ReadMax    ByteSize      `default:"32KiB" env:"COTTY_READ_MAX" help:"Most output one read returns. Older output beyond it is dropped."`
	TailLines  int           `default:"50" env:"COTTY_TAIL_LINES" help:"Lines a read returns when it has no previous read to continue from."`
	Timeout    time.Duration `default:"30s" env:"COTTY_TIMEOUT" help:"How long a read waits when the agent does not say."`
	MaxTimeout time.Duration `default:"10m" env:"COTTY_MAX_TIMEOUT" help:"Longest wait the agent may ask a read for."`
}

MCPCmd serves the sessions to an agent over MCP on stdio.

func (*MCPCmd) Run

func (m *MCPCmd) Run(c *Context) error

func (*MCPCmd) Validate

func (m *MCPCmd) Validate() error

type SessionInfo

type SessionInfo struct {
	Name       string    `json:"name"`
	ID         string    `json:"id"`
	Command    []string  `json:"command"`
	PID        int       `json:"pid"`
	StartedAt  time.Time `json:"started_at"`
	AgentInput bool      `json:"agent_input"`
}

SessionInfo describes a running session.

type WrapCmd

type WrapCmd struct {
	Name       string   `short:"n" required:"" help:"Session name: letters, digits, '.', '_' and '-', up to 32 characters."`
	BufferSize ByteSize `default:"1MiB" env:"COTTY_BUFFER_SIZE" help:"How much recent output to keep for the agent to read."`
	Command    []string `arg:"" passthrough:"" help:"Command to run, with its arguments."`
}

WrapCmd runs a command in a terminal shared with the agent.

func (*WrapCmd) Run

func (w *WrapCmd) Run(c *Context) error

Directories

Path Synopsis
cmd
cotty command

Jump to

Keyboard shortcuts

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