protocol

package module
v0.0.0-...-a8dba7a Latest Latest
Warning

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

Go to latest
Published: Apr 15, 2026 License: MIT Imports: 10 Imported by: 0

README

AgentD

agentd-protocol

Shared wire protocol types for the AgentD ecosystem

Go Reference MIT License Zero Dependencies


What This Is

A tiny Go module containing the shared wire protocol types used by both the AgentD daemon and AgentD relay server. By importing from a single source of truth, wire format drift between repos is impossible — the Go compiler enforces type identity.

Types

File Types Purpose
envelope.go RelayEnvelope Encrypted message envelope (sid, seq, enc, tid)
control.go ControlMessage, ControlType (10 constants), 9 payload structs Relay control protocol
policy.go PolicyJSON, PolicyMatchJSON Policy rule wire format
trace.go NewTraceID(), ValidTraceID() W3C-compatible trace ID generation

Control Types

register · join · heartbeat · ack · error · sync_policies
status_update · audit_entry · deactivate_developer · client_connected

Payload Types

RegisterPayload · JoinPayload · AckPayload · ErrorPayload
StatusUpdatePayload · AuditEntryPayload · DeactivateDeveloperPayload
ClientConnectedPayload · SyncPoliciesPayload

Usage

import protocol "github.com/hishamkaram/agentd-protocol"

env := protocol.RelayEnvelope{
    SessionID: "sess-123",
    Seq:       1,
    Encrypted: ciphertext,
    TraceID:   protocol.NewTraceID(),
}

Both agentd and agentd-relay use type aliases to re-export these types under their internal/relay package, so existing code using relay.RelayEnvelope continues to work unchanged.

Design Principles

  • Zero dependencies — only encoding/json, time, crypto/rand, encoding/hex from stdlib
  • Backward compatible — all new fields use omitempty; old clients produce identical JSON
  • W3C trace IDs — 32 lowercase hex chars, ready for OpenTelemetry upgrade
  • Roundtrip tested — every type has a JSON marshal/unmarshal roundtrip test

License

MIT

Documentation

Overview

Package protocol defines the shared wire protocol types for the AgentD relay system. Both the daemon (agentd) and relay server (agentd-relay) import this module to guarantee type identity across the WebSocket JSON contract.

This module has zero external dependencies — only encoding/json, time, crypto/rand, and encoding/hex.

Package protocol — git sync wire protocol (feature 172).

This file defines the request/response types, streaming progress events, and classified error codes for the git sync action family (branch list, branch switch, fetch, pull, push, cancel) introduced in feature 172.

The DAEMON is the source of truth for every Msg* constant in this file. A matching constant block lives in agentd/internal/session/wsserver_gitsync.go with an init() panic that cross-checks equality at daemon startup — the explicit drift prevention for the feature 170 incident class.

Index

Constants

View Source
const (
	GitDiffStatusModified string = "modified"
	GitDiffStatusAdded    string = "added"
	GitDiffStatusDeleted  string = "deleted"
	GitDiffStatusRenamed  string = "renamed"
	GitDiffStatusConflict string = "conflict"
	GitDiffStatusRemoved  string = "removed"
)

GitDiffStatus enum values for GitDiffResponse.Status.

View Source
const (
	GitNotAvailableReasonNotARepo       string = "not_a_git_repo"
	GitNotAvailableReasonGitMissing     string = "git_binary_missing"
	GitNotAvailableReasonWorkDirInvalid string = "work_dir_invalid"
)

GitNotAvailableReason enum values for GitNotAvailablePayload.Reason.

View Source
const (
	MsgGitBranchList           = "git_branch_list"
	MsgGitBranchListResponse   = "git_branch_list_response"
	MsgGitBranchSwitch         = "git_branch_switch"
	MsgGitBranchSwitchResponse = "git_branch_switch_response"
	MsgGitFetch                = "git_fetch"
	MsgGitFetchResponse        = "git_fetch_response"
	MsgGitPull                 = "git_pull"
	MsgGitPullResponse         = "git_pull_response"
	MsgGitPush                 = "git_push"
	MsgGitPushResponse         = "git_push_response"
	MsgGitSyncProgress         = "git_sync_progress"
	MsgGitSyncCancel           = "git_sync_cancel"
	MsgGitSyncCancelResponse   = "git_sync_cancel_response"
)

Message-type constants — DAEMON-side source of truth. Mirror MUST exist in agentd/internal/session/wsserver_gitsync.go with an init() panic cross-check that the two blocks agree at daemon startup.

View Source
const (
	GitSyncErrAuthFailed     = "auth_failed"
	GitSyncErrSSHPromptHang  = "ssh_prompt_hang"
	GitSyncErrNonFastForward = "non_fast_forward"
	GitSyncErrMergeConflict  = "merge_conflict"
	GitSyncErrDirtyWorkTree  = "dirty_work_tree"
	GitSyncErrNoUpstream     = "no_upstream"
	GitSyncErrNotAGitRepo    = "not_a_git_repo"
	GitSyncErrNetwork        = "network"
	GitSyncErrCanceled       = "canceled"
	GitSyncErrTimeout        = "timeout"
	GitSyncErrLockedIndex    = "locked_index"
	GitSyncErrInternal       = "internal"
)

Classified error codes. Every GitSync*Response.ErrorCode field holds one of these values (or the empty string when OK is true). The PWA maps each code to a user-facing ErrorBanner headline + suggested-action chips.

Variables

View Source
var (
	// ErrInvalidName indicates a server Name failed the name regex or a
	// reserved-name check.
	ErrInvalidName = errors.New("mcp: invalid server name")
	// ErrInvalidTransport indicates Transport is not stdio/sse/http.
	ErrInvalidTransport = errors.New("mcp: invalid transport")
	// ErrInvalidScope indicates Scope is not project/user.
	ErrInvalidScope = errors.New("mcp: invalid scope")
	// ErrInvalidCommand indicates a stdio Command is empty, too long, or
	// contains shell metacharacters.
	ErrInvalidCommand = errors.New("mcp: invalid command")
	// ErrInvalidArgs indicates stdio Args exceed count or length limits.
	ErrInvalidArgs = errors.New("mcp: invalid args")
	// ErrInvalidEnv indicates stdio Env has too many keys, or a key/value
	// that fails validation.
	ErrInvalidEnv = errors.New("mcp: invalid env")
	// ErrInvalidURL indicates sse/http URL is missing, unparseable, too long,
	// or uses a disallowed scheme.
	ErrInvalidURL = errors.New("mcp: invalid url")
	// ErrInvalidHeaders indicates sse/http Headers has too many keys or a
	// malformed key/value.
	ErrInvalidHeaders = errors.New("mcp: invalid headers")
	// ErrInvalidTransportFields indicates transport-exclusive fields are
	// populated for the wrong transport (e.g., URL set on stdio, Command set
	// on sse).
	ErrInvalidTransportFields = errors.New("mcp: transport-exclusive fields mismatched")
)

Validation sentinel errors. Use errors.Is to check for a specific class; the wrapper error from Validate contains additional context.

Functions

func NewTraceID

func NewTraceID() string

NewTraceID generates a random W3C-compatible trace ID (32 lowercase hex chars).

Panics on crypto/rand failure. This is an accepted deviation from the "no panic in library code" rule: crypto/rand failure indicates a catastrophic OS-level entropy issue where no cryptographic operation in the system can be trusted (AES-GCM encryption, key generation, token signing). Crashing immediately is safer than continuing with broken cryptography.

func ValidTraceID

func ValidTraceID(s string) bool

ValidTraceID returns true if s is a valid W3C trace ID (32 lowercase hex chars, non-zero).

func Validate

func Validate(cfg *MCPServerConfig) error

Validate runs the full validation suite for an MCPServerConfig and returns the first sentinel-wrapped error it finds. Callers should use errors.Is to match the specific ErrInvalidXxx class.

func ValidateName

func ValidateName(name string) error

ValidateName checks that name matches the MCP server name rules: byte length ≤64, matches ^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$, is not a reserved filename, and contains no path separators or leading dot.

func ValidateRemote

func ValidateRemote(cfg *MCPServerConfig) error

ValidateRemote checks the sse/http-transport fields of cfg: URL must be non-empty, ≤2048 bytes, parseable via net/url.Parse, and either use scheme=https OR have a loopback host (localhost/127.0.0.1/::1) with any scheme. Headers must respect count, RFC 7230 token syntax for keys, and length limits for values. Command/Args/Env must be empty.

func ValidateScope

func ValidateScope(scope MCPServerScope) error

ValidateScope checks that scope is exactly project or user. The CLI's third scope (`local`) is not supported by feature 169.

func ValidateStdio

func ValidateStdio(cfg *MCPServerConfig) error

ValidateStdio checks the stdio-transport fields of cfg: Command must be non-empty, ≤2048 bytes, and contain no shell metacharacters; Args must respect count and length limits; Env keys must match ^[A-Z_][A-Z0-9_]*$ and values must be ≤4096 bytes; there must be no URL or Headers set.

func ValidateTransport

func ValidateTransport(transport string) error

ValidateTransport checks that transport is exactly stdio, sse, or http. The Claude Code CLI also supports an in-process `sdk` transport, which is explicitly out of scope for user-manageable MCP servers — see spec Non-Goals.

Types

type AckPayload

type AckPayload struct {
	SessionID string `json:"sid"`
	ClientID  string `json:"client_id,omitempty"`
}

AckPayload is the relay's acknowledgement of a successful registration or join.

type AuditEntryPayload

type AuditEntryPayload struct {
	Timestamp   time.Time `json:"ts"`
	SessionID   string    `json:"session_id"`
	DeveloperID string    `json:"developer_id"`
	AgentType   string    `json:"agent"`
	EventType   string    `json:"event"`
	Tool        string    `json:"tool,omitempty"`
	InputHash   string    `json:"input_hash,omitempty"`
	Decision    string    `json:"decision,omitempty"`
	PolicyName  string    `json:"policy,omitempty"`
	CostUSD     float64   `json:"cost_usd,omitempty"`
}

AuditEntryPayload carries a single audit event from daemon to relay. InputHash is sha256hex of raw tool_input JSON bytes — NOT plaintext.

type ClientConnectedPayload

type ClientConnectedPayload struct {
	SessionID string `json:"session_id"`
}

ClientConnectedPayload is sent by the relay to the daemon when a PWA client connects or reconnects. The daemon uses this to replay message history.

type ClientCountPayload

type ClientCountPayload struct {
	Count     int    `json:"count"`
	SessionID string `json:"session_id"`
}

ClientCountPayload is sent by the relay to the daemon after every client join and disconnect. Informs the daemon of the current connected client count for replay optimization (first client: full replay, subsequent: session list only).

type ControlMessage

type ControlMessage struct {
	Type    ControlType     `json:"type"`
	Payload json.RawMessage `json:"payload"`
}

ControlMessage is the wire format for relay control protocol messages.

type ControlType

type ControlType string

ControlType discriminates control messages in the relay protocol.

const (
	CtrlRegister            ControlType = "register"
	CtrlJoin                ControlType = "join"
	CtrlHeartbeat           ControlType = "heartbeat" // reserved for future application-level keepalive; WebSocket ping/pong handles heartbeats
	CtrlAck                 ControlType = "ack"
	CtrlError               ControlType = "error"
	CtrlSyncPolicies        ControlType = "sync_policies"
	CtrlStatusUpdate        ControlType = "status_update"
	CtrlAuditEntry          ControlType = "audit_entry"
	CtrlDeactivateDeveloper ControlType = "deactivate_developer"
	CtrlClientConnected     ControlType = "client_connected"
	CtrlClientCount         ControlType = "client_count"
	CtrlKeyRotate           ControlType = "key_rotate"
)

Control message types for the relay protocol.

type DeactivateDeveloperPayload

type DeactivateDeveloperPayload struct {
	DeveloperID string `json:"developer_id"`
}

DeactivateDeveloperPayload is sent by the relay to the daemon when a developer is deactivated via SCIM.

type ErrorPayload

type ErrorPayload struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

ErrorPayload is the relay's error response to a failed control operation.

type GitBranch

type GitBranch struct {
	Name          string `json:"name"`
	IsCurrent     bool   `json:"is_current"`
	Upstream      string `json:"upstream,omitempty"`
	Ahead         int    `json:"ahead"`
	Behind        int    `json:"behind"`
	LastCommitAt  int64  `json:"last_commit_at"`
	LastCommitSha string `json:"last_commit_sha,omitempty"`
}

GitBranch is a single row in the branch switcher. Transient per request. Sorted by LastCommitAt descending for MRU behavior in the UI.

type GitBranchListRequest

type GitBranchListRequest struct {
	SessionID string `json:"session_id"`
	RequestID string `json:"request_id"`
}

GitBranchListRequest — PWA → daemon.

type GitBranchListResponse

type GitBranchListResponse struct {
	RequestID     string      `json:"request_id"`
	OK            bool        `json:"ok"`
	Error         string      `json:"error,omitempty"`
	ErrorCode     string      `json:"error_code,omitempty"`
	CurrentBranch string      `json:"current_branch,omitempty"`
	Branches      []GitBranch `json:"branches,omitempty"`
}

GitBranchListResponse — daemon → PWA. Echoes RequestID.

type GitBranchSwitchRequest

type GitBranchSwitchRequest struct {
	SessionID  string `json:"session_id"`
	RequestID  string `json:"request_id"`
	Branch     string `json:"branch"`
	StashDirty bool   `json:"stash_dirty"`
}

GitBranchSwitchRequest — PWA → daemon. First request always has StashDirty=false; on DirtyRequired=true response, the PWA opens the ConfirmRail and retries with StashDirty=true.

type GitBranchSwitchResponse

type GitBranchSwitchResponse struct {
	RequestID     string `json:"request_id"`
	OK            bool   `json:"ok"`
	Error         string `json:"error,omitempty"`
	ErrorCode     string `json:"error_code,omitempty"`
	Stderr        string `json:"stderr,omitempty"`
	NewBranch     string `json:"new_branch,omitempty"`
	StashRef      string `json:"stash_ref,omitempty"`
	DirtyRequired bool   `json:"dirty_required,omitempty"`
}

GitBranchSwitchResponse — daemon → PWA.

type GitDiffRequest

type GitDiffRequest struct {
	SessionID string `json:"session_id"`
	RequestID string `json:"request_id"`
	Path      string `json:"path"`
}

GitDiffRequest is the PWA → daemon request for one file's unified diff. Path must be repo-root-relative and must not escape the repo root.

type GitDiffResponse

type GitDiffResponse struct {
	RequestID   string `json:"request_id"`
	Path        string `json:"path"`
	Status      string `json:"status"`
	IsBinary    bool   `json:"is_binary"`
	IsRedacted  bool   `json:"is_redacted"`
	IsTruncated bool   `json:"is_truncated"`
	DiffText    string `json:"diff_text"`
	SizeBytes   int64  `json:"size_bytes"`
	Insertions  int    `json:"insertions"`
	Deletions   int    `json:"deletions"`
}

GitDiffResponse is the daemon → PWA response carrying one file's diff (or a safe placeholder state). DiffText is raw unified diff and is empty when IsBinary, IsRedacted, or Status is "removed".

type GitFetchRequest

type GitFetchRequest struct {
	SessionID string `json:"session_id"`
	RequestID string `json:"request_id"`
	Remote    string `json:"remote,omitempty"`
	Prune     bool   `json:"prune,omitempty"`
}

GitFetchRequest — PWA → daemon. Empty Remote triggers git-native default resolution (upstream-tracking → origin → fail). See FR-003a in spec.md.

type GitFetchResponse

type GitFetchResponse struct {
	RequestID string `json:"request_id"`
	OK        bool   `json:"ok"`
	Error     string `json:"error,omitempty"`
	ErrorCode string `json:"error_code,omitempty"`
	Stderr    string `json:"stderr,omitempty"`
	FetchedAt int64  `json:"fetched_at"`
}

GitFetchResponse — daemon → PWA.

type GitFileStatus

type GitFileStatus struct {
	Path        string `json:"path"`
	OrigPath    string `json:"orig_path,omitempty"`
	XY          string `json:"xy"`
	IsStaged    bool   `json:"is_staged"`
	IsUntracked bool   `json:"is_untracked"`
	IsConflict  bool   `json:"is_conflict"`
	IsRename    bool   `json:"is_rename"`
	Insertions  int    `json:"insertions"`
	Deletions   int    `json:"deletions"`
	IsBinary    bool   `json:"is_binary"`
	IsRedacted  bool   `json:"is_redacted"`
	SizeBytes   int64  `json:"size_bytes"`
}

GitFileStatus describes one dirty file reported by `git status --porcelain=v2`. Shipped inside GitStatusPayload.Files. Paths are repo-root-relative and never absolute.

type GitNotAvailablePayload

type GitNotAvailablePayload struct {
	Reason string `json:"reason"`
	Detail string `json:"detail"`
}

GitNotAvailablePayload is a one-shot notice emitted when gitwatch cannot observe a session (WorkDir is not a git repo, or git binary missing).

type GitPullRequest

type GitPullRequest struct {
	SessionID string `json:"session_id"`
	RequestID string `json:"request_id"`
	Rebase    bool   `json:"rebase,omitempty"`
}

GitPullRequest — PWA → daemon. Rebase=false (default) → --ff-only.

type GitPullResponse

type GitPullResponse struct {
	RequestID    string `json:"request_id"`
	OK           bool   `json:"ok"`
	Error        string `json:"error,omitempty"`
	ErrorCode    string `json:"error_code,omitempty"`
	Stderr       string `json:"stderr,omitempty"`
	NewHead      string `json:"new_head,omitempty"`
	FilesChanged int    `json:"files_changed,omitempty"`
}

GitPullResponse — daemon → PWA.

type GitPushRequest

type GitPushRequest struct {
	SessionID      string `json:"session_id"`
	RequestID      string `json:"request_id"`
	Remote         string `json:"remote,omitempty"`
	ForceWithLease bool   `json:"force_with_lease,omitempty"`
	Force          bool   `json:"force,omitempty"`
	SetUpstream    bool   `json:"set_upstream,omitempty"`
}

GitPushRequest — PWA → daemon. Force semantics:

ForceWithLease=true, Force=false → --force-with-lease (safe)
Force=true, ForceWithLease=false → raw --force (unsafe, advanced UI)
both false → plain push
both true → daemon rejects with GitSyncErrInternal (ambiguous)

type GitPushResponse

type GitPushResponse struct {
	RequestID string `json:"request_id"`
	OK        bool   `json:"ok"`
	Error     string `json:"error,omitempty"`
	ErrorCode string `json:"error_code,omitempty"`
	Stderr    string `json:"stderr,omitempty"`
	PushedRef string `json:"pushed_ref,omitempty"`
}

GitPushResponse — daemon → PWA.

type GitStatusPayload

type GitStatusPayload struct {
	RepoRoot        string          `json:"repo_root"`
	Files           []GitFileStatus `json:"files"`
	TotalInsertions int             `json:"total_insertions"`
	TotalDeletions  int             `json:"total_deletions"`
	GeneratedAt     int64           `json:"generated_at"`

	// Feature 172 additive fields — all omitempty for backward compat.
	Branch        string `json:"branch,omitempty"`
	Upstream      string `json:"upstream,omitempty"`
	Ahead         int    `json:"ahead,omitempty"`
	Behind        int    `json:"behind,omitempty"`
	LastFetchedAt int64  `json:"last_fetched_at,omitempty"`
}

GitStatusPayload is the full per-session status snapshot returned by GetGitStatus and carried in MsgGitStatusUpdate pushes. Files is sorted ascending by path and capped at 500 entries.

Feature 172 extended this struct with five omitempty fields (Branch, Upstream, Ahead, Behind, LastFetchedAt) so the PWA's BranchChip and FreshnessPill can render current-branch context alongside the existing file-level status. All new fields are omitempty — older daemons emit the original 5-field shape and older PWAs ignore the new fields.

type GitStatusRequest

type GitStatusRequest struct {
	SessionID string `json:"session_id"`
	RequestID string `json:"request_id"`
}

GitStatusRequest is the PWA → daemon request to fetch the current status snapshot for a session. The response body is a GitStatusPayload.

type GitSyncCancelRequest

type GitSyncCancelRequest struct {
	SessionID string `json:"session_id"`
	RequestID string `json:"request_id"`
	TargetID  string `json:"target_id"`
}

GitSyncCancelRequest — PWA → daemon.

type GitSyncCancelResponse

type GitSyncCancelResponse struct {
	RequestID string `json:"request_id"`
	TargetID  string `json:"target_id"`
	OK        bool   `json:"ok"`
	Error     string `json:"error,omitempty"`
	ErrorCode string `json:"error_code,omitempty"`
}

GitSyncCancelResponse — daemon → PWA. OK=true means the target's context.CancelFunc was found and invoked; the target op will emit its own terminal response shortly after with ErrorCode=canceled.

type GitSyncProgressPayload

type GitSyncProgressPayload struct {
	RequestID string `json:"request_id"`
	Op        string `json:"op"`
	Stage     string `json:"stage"`
	Percent   int    `json:"percent,omitempty"`
	Line      string `json:"line,omitempty"`
}

GitSyncProgressPayload is a streaming daemon → PWA event emitted during long-running fetch/pull/push/switch operations. Lossy on the daemon side (buffered channel with drop-oldest on full). The terminal response is always delivered.

type JoinPayload

type JoinPayload struct {
	SessionID string `json:"sid"`
	JWT       string `json:"jwt"`
	ClientID  string `json:"client_id,omitempty"`
}

JoinPayload is sent by the mobile client to join a session. JWT carries the clientToken from QRPayload.token.

type KeyRotatePayload

type KeyRotatePayload struct {
	NewKeyHMAC    string `json:"new_key_hmac"`
	PrevKeyHMAC   string `json:"prev_key_hmac"`
	PrevExpiresAt int64  `json:"prev_expires_at"`
	Epoch         uint64 `json:"epoch"`
}

KeyRotatePayload is sent by the daemon to the relay to update the session's auth KeyHMAC during automatic key rotation. The relay retains the previous HMAC until PrevExpiresAt so in-flight client tokens pass validation during the grace window. Fields are NOT omitempty because the relay needs all four.

type MCPListPayload

type MCPListPayload struct {
	RequestID string         `json:"request_id,omitempty"`
	Scope     MCPServerScope `json:"scope,omitempty"`
	SessionID string         `json:"session_id,omitempty"`
}

MCPListPayload is the PWA → daemon request for the merged MCP server list. Empty Scope means both scopes; SessionID is required for project-scope resolution. RequestID is an opaque client-generated identifier echoed back in the response so the PWA can match replies to in-flight requests (feature 170).

type MCPListResponse

type MCPListResponse struct {
	RequestID      string                 `json:"request_id,omitempty"`
	Servers        []MCPServerConfig      `json:"servers"`
	Status         []MCPServerStatusEntry `json:"status,omitempty"`
	ProjectWorkdir string                 `json:"project_workdir,omitempty"`
}

MCPListResponse is the daemon → PWA response to mcp_list_servers. Servers is ordered deterministically: user scope first, then project, sorted by name within each scope. Status is empty when no session is active. RequestID echoes the originating request's request_id so the PWA can route the response to the right in-flight callback (feature 170).

type MCPMutationPayload

type MCPMutationPayload struct {
	RequestID string          `json:"request_id,omitempty"`
	SessionID string          `json:"session_id,omitempty"`
	Server    MCPServerConfig `json:"server"`
}

MCPMutationPayload is the PWA → daemon request for add/update operations. SessionID is required for project-scope mutations so the daemon can resolve the target workdir; user-scope mutations may omit it. RequestID is echoed back in the response (feature 170).

type MCPMutationResponse

type MCPMutationResponse struct {
	RequestID     string                 `json:"request_id,omitempty"`
	OK            bool                   `json:"ok"`
	Error         string                 `json:"error,omitempty"`
	ErrorCode     string                 `json:"error_code,omitempty"`
	AppliedToLive bool                   `json:"applied_to_live"`
	LiveStatus    []MCPServerStatusEntry `json:"live_status,omitempty"`
	Server        *MCPServerConfig       `json:"server,omitempty"`
}

MCPMutationResponse is the daemon → PWA response for add/update/remove/ toggle/reconnect operations. AppliedToLive is true when the SDK's SetMCPServers call succeeded against a live session; false for user-scope mutations without an active session, or when the session ended mid-op. RequestID echoes the originating request's request_id (feature 170).

type MCPReconnectPayload

type MCPReconnectPayload struct {
	RequestID string `json:"request_id,omitempty"`
	SessionID string `json:"session_id"`
	Name      string `json:"name"`
}

MCPReconnectPayload is the PWA → daemon request to force a reconnect of a named MCP server on a live session. SessionID is required — reconnect is session-scoped. Shares MCPMutationResponse for the reply. RequestID is echoed back (feature 170).

type MCPRemovePayload

type MCPRemovePayload struct {
	RequestID string         `json:"request_id,omitempty"`
	SessionID string         `json:"session_id,omitempty"`
	Scope     MCPServerScope `json:"scope"`
	Name      string         `json:"name"`
}

MCPRemovePayload is the PWA → daemon request to delete a server from a given scope. Shares MCPMutationResponse for the reply. RequestID is echoed back (feature 170).

type MCPServerConfig

type MCPServerConfig struct {
	Name      string            `json:"name"`
	Scope     MCPServerScope    `json:"scope"`
	Transport string            `json:"transport"`
	Enabled   bool              `json:"enabled"`
	Command   string            `json:"command,omitempty"`
	Args      []string          `json:"args,omitempty"`
	Env       map[string]string `json:"env,omitempty"`
	URL       string            `json:"url,omitempty"`
	Headers   map[string]string `json:"headers,omitempty"`
}

MCPServerConfig is the canonical representation of a single MCP server configuration. Field set depends on Transport:

  • transport=stdio : Command (required), Args (optional), Env (optional)
  • transport=sse : URL (required), Headers (optional)
  • transport=http : URL (required), Headers (optional)

Env and Headers values are secrets — never log them.

type MCPServerScope

type MCPServerScope string

MCPServerScope identifies where an MCP server configuration is persisted. `project` entries live in `<workdir>/.mcp.json`; `user` entries live in `~/.claude.json`. Claude Code CLI's third scope (`local`) is explicitly out of scope for feature 169 — see spec.md Non-Goals.

const (
	// MCPScopeProject persists the server in <workdir>/.mcp.json.
	MCPScopeProject MCPServerScope = "project"
	// MCPScopeUser persists the server in ~/.claude.json.
	MCPScopeUser MCPServerScope = "user"
)

MCPServerScope values.

type MCPServerStatusEntry

type MCPServerStatusEntry struct {
	Name       string         `json:"name"`
	Status     string         `json:"status"`
	Message    string         `json:"message,omitempty"`
	ToolCount  int            `json:"tool_count,omitempty"`
	ShadowedBy MCPServerScope `json:"shadowed_by,omitempty"`
}

MCPServerStatusEntry is the live connection state for a single MCP server as reported by the Go SDK's client.MCPServerStatus(). Not persisted — the daemon computes it on demand. `disabled` is synthesized locally when a config entry has Enabled=false (the SDK has no entry for those servers).

type MCPServersChangedPayload

type MCPServersChangedPayload struct {
	Scope      MCPServerScope `json:"scope"`
	SessionID  string         `json:"session_id,omitempty"`
	Action     string         `json:"action"`
	ServerName string         `json:"server_name"`
}

MCPServersChangedPayload is the daemon → PWA broadcast emitted after every successful mutation. Clients re-dispatch mcp_list_servers to refresh their view. Action is diagnostic only (add|update|remove|toggle|reconnect).

type MCPTogglePayload

type MCPTogglePayload struct {
	RequestID string         `json:"request_id,omitempty"`
	SessionID string         `json:"session_id,omitempty"`
	Scope     MCPServerScope `json:"scope"`
	Name      string         `json:"name"`
	Enabled   bool           `json:"enabled"`
}

MCPTogglePayload is the PWA → daemon request to enable/disable a server without rewriting its full config. Shares MCPMutationResponse for the reply. RequestID is echoed back (feature 170).

type PolicyJSON

type PolicyJSON struct {
	Name      string          `json:"name"`
	Match     PolicyMatchJSON `json:"match"`
	Action    string          `json:"action"`
	Approvers []string        `json:"approvers,omitempty"`
	TimeoutS  int             `json:"timeout_s,omitempty"`
	Reason    string          `json:"reason,omitempty"`
}

PolicyJSON represents a single policy rule in the relay wire format.

type PolicyMatchJSON

type PolicyMatchJSON struct {
	Tool        []string `json:"tool,omitempty"`
	FilePattern string   `json:"file_pattern,omitempty"`
	Branch      string   `json:"branch,omitempty"`
	Command     string   `json:"command,omitempty"`
	RiskLevel   []string `json:"risk_level,omitempty"`
}

PolicyMatchJSON represents the match criteria for a policy rule.

type RegisterPayload

type RegisterPayload struct {
	SessionID   string `json:"sid"`
	KeyHMAC     string `json:"key_hmac"`
	AgentType   string `json:"agent"`
	ProjectName string `json:"project"`
	DisplayName string `json:"display"`
	DeveloperID string `json:"dev_id,omitempty"`
}

RegisterPayload is sent by the daemon to register a session on the relay.

type RelayEnvelope

type RelayEnvelope struct {
	SessionID string `json:"sid"`
	Seq       uint64 `json:"seq"`
	Encrypted []byte `json:"enc"`
	TraceID   string `json:"tid,omitempty"` // W3C trace-id (32 hex chars); optional for backward compat
}

RelayEnvelope is the wire format for encrypted session messages routed between daemon and PWA via the relay. The relay routes by SessionID and NEVER inspects the Encrypted payload.

type StatusUpdatePayload

type StatusUpdatePayload struct {
	SessionID   string  `json:"sid"`
	State       string  `json:"state"`
	CostUSD     float64 `json:"cost_usd,omitempty"`
	Project     string  `json:"project,omitempty"`
	AgentType   string  `json:"agent,omitempty"`
	DeveloperID string  `json:"dev_id,omitempty"`
	CreatedAt   int64   `json:"created_at,omitempty"`
}

StatusUpdatePayload is sent by the daemon to the relay every 30s with current session state. The relay intercepts this and updates its in-memory state; it is never forwarded to clients.

type SyncPoliciesPayload

type SyncPoliciesPayload struct {
	Policies []PolicyJSON `json:"policies"`
}

SyncPoliciesPayload is sent by relay to daemon after CtrlAck. Carries the current org/team policy set.

Jump to

Keyboard shortcuts

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