HomeDocsArchitecture › 9. `rysh-proto`

9. rysh-proto — Reference Schemas

rysh-proto (module github.com/rysh-ai/rysh-proto, proto3) defines the message shapes used across Rysh. Important: these are reference schemas only. The live NATS wire format is JSON, and the canonical serialization types are the Go structs in rysh-shared/msg. The proto files document intent and shape; they are not used for serialization at runtime.

Package naming. Every .proto declares the protobuf package rysh.v1, but each file's go_package option (and the generated Go) uses a distinct per-directory package — conversationpb, panemsgpb, memorypb, envelopepb. There is no single Go import package called rysh.v1.

The module contains both .proto sources and generated .pb.go files. As of the May 2026 repo split, rysh-proto is now a standalone git repository (git@github.com:rysh-ai/rysh-proto.git) and is .gitignored from the monorepo root — the directory is still physically present and is still referenced by go.work via a local replace directive, so it remains a workspace member at build time. (The same externally-managed-repo treatment applies to rysh-shared and rysh-chrome-plugin.) The runtime simply mirrors these definitions as hand-maintained Go structs.


9.1 Why proto-as-documentation?

graph LR
    Proto[".proto files
(reference schemas)"] -.documents shape.-> GoStructs["rysh-shared/msg
Go structs (canonical)"] GoStructs -->|JSON| Envelope["NATSEnvelope (JSON)"] Envelope -->|publish| NATS["NATS subjects"] Proto -.->|generated| PbGo[".pb.go (not on the wire)"]

The team chose JSON-on-the-wire (simpler debugging, no codegen coupling for the TS extension and dynamic codec) but kept proto as a single source of truth for the message contracts. Note the enum names differ in case from the Go constants (proto CONVERSATION_TYPE_SHELL/_AI vs Go "shell"/"ai").

The "reference only" status is documented in Go, not in proto. The proto files carry only ordinary descriptive comments (e.g. envelope.proto says payload is the "protobuf-serialized inner message"). The statement that proto is reference-only and the wire is JSON comes from comments in rysh-shared/msg/conversation.go. So the proto and the runtime have genuinely diverged: the proto describes a protobuf encoding that the runtime does not use.


9.2 The four packages

conversationpb/conversation.proto — the core schema

Verbatim (package rysh.v1; syntax = "proto3";):

enum ConversationType {
  CONVERSATION_TYPE_UNSPECIFIED = 0; CONVERSATION_TYPE_SHELL = 1; CONVERSATION_TYPE_AI = 2;
  CONVERSATION_TYPE_RYSH = 3; CONVERSATION_TYPE_CHAT = 4; CONVERSATION_TYPE_EMAIL = 5;
  CONVERSATION_TYPE_SLACK = 6; CONVERSATION_TYPE_CHATBOT = 7;
}
enum TurnType      { TURN_TYPE_UNSPECIFIED = 0; TURN_TYPE_QUESTION = 1; TURN_TYPE_ANSWER = 2; }
enum InputType     { INPUT_TYPE_UNSPECIFIED = 0; INPUT_TYPE_SHELL = 1; INPUT_TYPE_PROMPT = 2;
                     INPUT_TYPE_COMMAND = 3; INPUT_TYPE_APPROVAL = 4; INPUT_TYPE_MESSAGE = 5; }
enum MessageSource { MESSAGE_SOURCE_UNSPECIFIED = 0; MESSAGE_SOURCE_HUMAN = 1; MESSAGE_SOURCE_AI = 2;
                     MESSAGE_SOURCE_EXTERNAL = 3; MESSAGE_SOURCE_AGENT = 4; MESSAGE_SOURCE_SUBAGENT = 5;
                     MESSAGE_SOURCE_HUMANOID = 6; MESSAGE_SOURCE_SYSTEM = 7; }

message ConversationMessage {
  string turn_id = 1;              TurnType turn_type = 2;
  ConversationType conversation_type = 3;  InputType input_type = 4;
  MessageSource message_source = 5; string content = 6;
  int64 timestamp_ms = 7;          bool sensitive = 8;
  bool subject_to_share = 9;       string role = 10;   // visitor, assistant, human, system
  bool streaming = 11;             // partial streaming chunk
}

This single type replaces 12 legacy per-mode message types. (The Go struct adds an Origin field absent from proto.)

panemsgpb/pane_messages.proto

  • MsgConversationAppend{ConversationMessage message} → output topics.
  • MsgConversationHistoryAppend{ConversationMessage message} → history topics.

These replace six per-mode MsgPane*OutputAppend and six MsgPane*HistoryAppend types.

memorypb/memory.proto

  • MemoryEntry{id, summary, turn_ids[], mode, created_at_ms, turn_count}.
  • MemoryState{pane_id, mode, entries[], total_summarized_turns}.

envelopepb/envelope.proto

// NATSEnvelope is the wire format for all inter-actor messages on NATS.
message NATSEnvelope {
  string type_tag = 1;  // message type discriminator (e.g. "MsgConversationAppend")
  string reply_to = 2;  // NATS reply subject; empty for fire-and-forget
  bytes  payload  = 3;  // protobuf-serialized inner message
}

This is where proto and runtime diverge most visibly. The proto declares full field names (type_tag/reply_to/payload) and a bytes (protobuf) payload. The runtime Go NATSEnvelope instead uses short JSON keys (t/r/p) with a JSON payload (json.RawMessage), and the Chrome extension uses base64-encoded JSON. None of these are the protobuf encoding the proto describes.


9.3 Relationship to the runtime

Proto type Runtime Go type (rysh-shared/msg) On the wire
ConversationMessage ConversationMessage (+ extra Origin field) JSON inside envelope p
MsgConversationAppend / …HistoryAppend same names JSON, tag in envelope t
MemoryEntry / MemoryState same names JSON
NATSEnvelope{type_tag, reply_to, bytes payload} NATSEnvelope{t, r, json.RawMessage p} JSON (proto says protobuf)

Note also that the TypeTags the system actually uses on the wire (MsgAgenticPrompt, MsgApprovalResponse, MsgBrowserActionRequest, …) are not defined in proto at all — only the two MsgConversation* wrappers are. The full tag set lives in rysh-shared/msg (§3.5).

The Go ConversationMessage adds an Origin *MessageOrigin field (not in proto) used for tab-mirroring provenance. See §3.3.


9.4 Caveat

Do not assume protobuf binary encoding anywhere in Rysh. Treat rysh-proto as living documentation of the message contracts; change the Go structs in rysh-shared/msg to change actual behavior, and keep the proto in sync for clarity.