Docs/SDK and API/gRPC API

gRPC API

The gRPC server is Seshat's process boundary for other languages, remote orchestration, and service-to-service runtime access. This page documents the real contract as implemented today: the proto, the server behavior, session semantics, streaming protocol, code generation, extension path, and current gaps that still need to be completed.

Overview

Seshat currently has three core runtime entry points: the CLI app, the embedded Go SDK, and `cmd/grpc`. The Go SDK is the native same-process integration for Go hosts. gRPC is the network or language boundary when your host is not Go, when you want a separate runtime service, or when a future official SDK for Python, JS, Rust, Java, or another language needs a transport contract first.

Naming note

Some older repository docs still mention `nexus.proto` and `nexus.NexusService`. The current source of truth is `pkg/grpc/proto/seshat.proto`, package `seshat`, service `SeshatService`, with method paths such as /seshat.SeshatService/Query.

Use gRPC when

Your host language is not Go, you want to keep the runtime in a separate process, or you need a stable transport contract for polyglot clients.

Use Go SDK when

Your host is Go and you want full in-process control over sessions, providers, prompt layers, tools, permissions, hooks, and event handling.

Security posture

`cmd/grpc` has no authentication layer of its own. Treat it as local or trusted-network infrastructure, or put it behind your own auth, TLS, and policy boundary.

Runtime behavior

Behind gRPC, the server still builds a real `sdk.Client`, creates or loads persistent sessions, streams runtime events, and uses the same provider registry and tool system as the other entry points.

Start Server

The entry point is `cmd/grpc`. By default it listens on `:50051` and builds the runtime host config from the same config loader used elsewhere in Seshat.

Development
ANTHROPIC_API_KEY=sk-ant-... SESHAT_MODEL=anthropic:claude-sonnet-4-20250514 go run ./cmd/grpc
Built binary
make build-grpc
SESHAT_GRPC_ENABLE_REFLECTION=true ./bin/seshat-grpc
  • The server registers `SeshatService` only.
  • Reflection is disabled by default and must be enabled explicitly.
  • Shutdown is graceful on `SIGINT` and `SIGTERM`.

Server Config

There are two config layers to understand. First, the gRPC server has its own transport-level env vars. Second, it inherits the shared runtime host config from `pkg/config`, which controls the model default, session persistence, working directory, provider credentials, storage, browser settings, and more.

gRPC-specific environment

NameNotesStatus
SESHAT_GRPC_PORTListening port. Default: `50051`.
SESHAT_GRPC_MAX_CONCURRENT_RPCSMapped to `grpc.MaxConcurrentStreams`. Default: `10`.
SESHAT_GRPC_KEEPALIVE_TIMEParsed as a Go duration and used for keepalive enforcement. Default: `30s`.
SESHAT_GRPC_ENABLE_REFLECTIONEnables gRPC reflection for tools like `grpcurl` without passing the proto explicitly. Default: disabled.
SESHAT_VERSIONReturned by `HealthCheck` as the server version string.

Shared runtime environment reused by gRPC

NameNotesStatus
SESHAT_MODELDefault model when the request does not specify one.
SESHAT_CWDWorking directory inherited by the runtime sessions created behind gRPC.
SESHAT_DB_PATHBase runtime SQLite path. Also becomes the default session DB path when `SESHAT_SESSION_DB_PATH` is not set.
SESHAT_SESSION_DB_PATHPersistent session store used for `context_id` resume flows.
SESHAT_PROVIDER_BASE_URLUseful for provider-compatible gateways or custom endpoints.
SESHAT_STORAGE_PROVIDER + SESHAT_STORAGE_*Object storage backend configuration reused by the embedded runtime.
SESHAT_BROWSER_REMOTE_CONTROL_URL / SESHAT_BROWSER_EXECUTABLE_PATHBrowser runtime settings reused if browser tools are available in the session surface.
Provider keysThe server reuses the same provider env resolution as the CLI and Go SDK, for example `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`, `CODEX_API_KEY`, `CODEX_ACCESS_TOKEN`, and others.
Headless by design

`cmd/grpc` forces sdk.PermissionModeNever. That means the gRPC surface does not open interactive approval prompts. If you need interactive permissions, build your own host experience on top of the Go SDK instead of relying on the stock gRPC server.

Service Contract

The current proto defines more than what `cmd/grpc` actually exposes. This table separates the live `SeshatService` surface from the proto-only services that still need implementation and server registration.

NameTypeBehaviorNotesStatus
QueryUnaryOne request, one final response.Creates or loads a runtime session, executes one turn, then returns the final assistant text plus usage.Implemented
QueryStreamServer streamingStreams chunks, runtime events, then a final response.Best surface for live UIs, logs, or other language SDKs that want incremental output.Implemented
ListSkillsUnaryLists discovered skills.Supports source filtering with `all`, `bundled`, `file`, or `mcp`.Implemented
GetSkillDetailsUnaryReturns skill metadata for one skill.Currently returns the `Skill` metadata only; the `prompt` field in the proto is not populated yet.Implemented
ListMCPUnaryLists MCP server statuses.Returns server name, status, tool count, and last error.Implemented
ConnectMCPUnaryRegisters then reconnects an MCP server.Supports `stdio`, `http`, `sse`, and `ws`/`websocket`.Implemented
DisconnectMCPUnaryDisconnects one MCP server.Only disconnects by name; useful for runtime-controlled extension management.Implemented
GetModelsUnaryLists models from the provider registry.This is registry-driven, not only “currently configured” models.Implemented
HealthCheckUnaryReturns status, version, and uptime.Current implementation is shallow: it does not re-check downstream providers or storage on every call.Implemented
FileServiceService declared in protoRead/write/edit/glob/grep surface.Declared in `seshat.proto` but not implemented or registered in `cmd/grpc`.Proto only
SystemServiceService declared in protoBash + system info surface.Declared in `seshat.proto` but not implemented or registered in `cmd/grpc`.Proto only

Unary Query

`Query` is the simplest call: one request, one completed turn, one final response. The server either creates a new persisted session or loads an existing one from `context_id`, applies any requested tool allowlist, runs the turn, and returns the latest assistant text plus usage totals.

`QueryRequest` fields and actual server behavior

NameNotesStatus
promptRequired. Empty prompts are rejected with `InvalidArgument`.
modelOptional. Best practice is `provider:model`, for example `anthropic:claude-sonnet-4-20250514` or `codex:gpt-5.3-codex`.
toolsOptional allowlist. If you pass tools, every other currently-registered tool is unregistered for that session. Unknown tool names return `InvalidArgument`.
streamDeclared in the proto but currently not used by `cmd/grpc`. In practice, you choose streaming by calling `QueryStream` instead of `Query`.
context_idOptional persisted session id. If present, the server loads the existing session instead of creating a new one. The returned `conversation_id` is that session id.
temperatureDeclared in the proto but currently not wired into `buildSDKClientConfig`. It is a real contract gap today.
max_tokensWired. Overrides host config max output tokens when greater than zero.
api_keyPer-request credential override. Useful for direct API-key injection and especially for bearer-style Codex / OAuth handoff over gRPC.
grpcurl / unary query
grpcurl   -plaintext   -import-path pkg/grpc/proto   -proto seshat.proto   -d '{
    "prompt": "Audit this repository and summarize the biggest risks.",
    "model": "anthropic:claude-sonnet-4-20250514",
    "tools": ["read_file", "grep", "glob"],
    "max_tokens": 1800
  }'   localhost:50051   seshat.SeshatService/Query
grpcurl / resume with context_id
grpcurl   -plaintext   -import-path pkg/grpc/proto   -proto seshat.proto   -d '{
    "prompt": "Continue from the previous analysis and propose a patch plan.",
    "context_id": "sess-42"
  }'   localhost:50051   seshat.SeshatService/Query
  • `conversation_id` in the response is the underlying Seshat session id.
  • Passing `tools` acts as an allowlist, not an additive tool request.
  • Unknown tool names fail early with `InvalidArgument`.
  • If `api_key` is present, it overrides host credential resolution for that request.

Streaming

`QueryStream` is the main protocol for live experiences. It reuses the same runtime execution path, but instead of waiting for the full turn it forwards response chunks and structured runtime events as they are emitted, then closes with one final message containing the completed assistant text and token usage totals.

`QueryResponse.item_type` values

NameNotesStatus
chunkCarries incremental assistant text in `content` and a structured `chunk` object with `type`, `delta_type`, and `delta`.
runtime_eventCarries structured engine events such as turn start, tool progress, stop reason, token usage snapshots, and tool metadata.
finalCarries the final assistant text, `conversation_id`, `stopped`, and final token usage totals.
grpcurl / streaming query
grpcurl   -plaintext   -import-path pkg/grpc/proto   -proto seshat.proto   -d '{
    "prompt": "Inspect the project and stream your findings step by step.",
    "model": "anthropic:claude-sonnet-4-20250514"
  }'   localhost:50051   seshat.SeshatService/QueryStream
Important streaming nuance

The server streams what the session callback emits. That gives you real incremental output and runtime events, but it is not documented as a provider-native token-perfect transport contract. In other words, treat it as a runtime stream, not as a raw vendor stream.

Skills, MCP, Models, and Health

gRPC is not only for prompting. The server also exposes part of the runtime surface around skills discovery, MCP server lifecycle, provider registry introspection, and health reporting.

grpcurl / auxiliary methods
# reflection mode if enabled
grpcurl -plaintext localhost:50051 list

grpcurl -plaintext -import-path pkg/grpc/proto -proto seshat.proto   -d '{"source_filter":"all"}' localhost:50051 seshat.SeshatService/ListSkills

grpcurl -plaintext -import-path pkg/grpc/proto -proto seshat.proto   -d '{}' localhost:50051 seshat.SeshatService/GetModels

grpcurl -plaintext -import-path pkg/grpc/proto -proto seshat.proto   -d '{"name":"github","type":"stdio","command":"npx","args":["-y","@modelcontextprotocol/server-github"]}'   localhost:50051 seshat.SeshatService/ConnectMCP

grpcurl -plaintext -import-path pkg/grpc/proto -proto seshat.proto   -d '{}' localhost:50051 seshat.SeshatService/HealthCheck
  • `ListSkills` reads from the current skills discovery path using the server working directory.
  • `ConnectMCP` persists an MCP server config, then reconnects it immediately through the runtime manager.
  • `GetModels` lists models from the provider catalog, not only from currently-authenticated providers.
  • `HealthCheck` returns server uptime and version, but it is not a full dependency readiness probe.

Client Usage

Today, gRPC is the cleanest cross-language contract Seshat has. The Go SDK is native embedding. Future Python, JS, Rust, Java, or C# SDKs can realistically start as higher-level wrappers around this gRPC surface, then grow richer runtime ergonomics later.

Go client

Go gRPC client
conn, err := grpc.Dial(
    "localhost:50051",
    grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

client := pb.NewSeshatServiceClient(conn)

resp, err := client.Query(ctx, &pb.QueryRequest{
    Prompt: "Review this repository and propose a refactor plan.",
    Model:  "anthropic:claude-sonnet-4-20250514",
    Tools:  []string{"read_file", "grep", "glob"},
})
if err != nil {
    log.Fatal(err)
}

fmt.Println(resp.Content)
fmt.Println(resp.ConversationId)
fmt.Println(resp.TokenUsage.TotalTokens)

Python client

Python gRPC client
import grpc
from gen import seshat_pb2, seshat_pb2_grpc

channel = grpc.insecure_channel("localhost:50051")
client = seshat_pb2_grpc.SeshatServiceStub(channel)

resp = client.Query(
    seshat_pb2.QueryRequest(
        prompt="Summarize this project architecture.",
        model="anthropic:claude-sonnet-4-20250514",
        max_tokens=1200,
    )
)
print(resp.content)
print(resp.conversation_id)

stream = client.QueryStream(
    seshat_pb2.QueryRequest(
        prompt="Stream a code review of this repository.",
        context_id=resp.conversation_id,
    )
)
for item in stream:
    if item.item_type == "chunk":
        print(item.content, end="", flush=True)
    elif item.item_type == "runtime_event":
        print(f"\n[event] {item.runtime_event.type} {item.runtime_event.tool_name}")
    elif item.item_type == "final":
        print(f"\nfinal tokens={item.token_usage.total_tokens}")
About future non-Go SDKs

Yes, gRPC is the most obvious foundation for official SDKs in other languages. The generated stubs alone are not enough for a polished developer experience, but they provide the stable transport boundary those SDKs can wrap: session resume, auth injection, stream aggregation, error normalization, and helper abstractions can all be layered on top of this contract.

Codegen & Regeneration

If you modify `pkg/grpc/proto/seshat.proto`, you must regenerate the Go stubs and then rebuild or retest the server. The generated Go files live in `pkg/grpc/seshat/`.

Regenerate Go stubs from the repo root

Go proto regeneration
PATH="$HOME/.local/bin:$(go env GOPATH)/bin:$PATH" protoc   --proto_path=pkg/grpc/proto   --go_out=.   --go_opt=module=github.com/EngineerProjects/seshat   --go-grpc_out=.   --go-grpc_opt=module=github.com/EngineerProjects/seshat   pkg/grpc/proto/seshat.proto

Generate Python stubs

Python proto generation
python -m grpc_tools.protoc   -I pkg/grpc/proto   --python_out=./gen   --grpc_python_out=./gen   pkg/grpc/proto/seshat.proto

Generate Node / JS stubs

Node proto generation
# Node / JS stub generation example
npx grpc_tools_node_protoc   --proto_path=pkg/grpc/proto   --js_out=import_style=commonjs,binary:./gen   --grpc_out=grpc_js:./gen   pkg/grpc/proto/seshat.proto
  • After regeneration, rebuild with go build ./cmd/grpc.
  • Then verify behavior with go test ./cmd/grpc/....
  • If you changed generated package names or method signatures, update any website examples and consumer wrappers as well.

How To Extend

Completing the gRPC surface is more than adding lines to the proto. A real extension path has four layers: the `.proto` contract, regenerated stubs, server implementation, and bufconn tests that lock the behavior down.

  1. Edit `pkg/grpc/proto/seshat.proto` and add or change the RPC or message you need.
  2. Regenerate the Go stubs in `pkg/grpc/seshat/` using `protoc`.
  3. Implement the server method in `cmd/grpc/main.go` and map it to real runtime behavior instead of placeholder logic.
  4. If you add a brand new service, register it explicitly on the gRPC server. The proto declaration alone does not expose it.
  5. Add bufconn-backed integration tests in `cmd/grpc/main_test.go` so request validation, streaming shape, and cleanup behavior stay stable.
  6. Rebuild, test, and then update docs so transport examples stay aligned with the real contract.
Registering an additional service
type FileServer struct {
    pb.UnimplementedFileServiceServer
}

func (s *FileServer) Read(ctx context.Context, req *pb.FileReadRequest) (*pb.FileReadResponse, error) {
    // map request to the runtime or filesystem layer here
    return &pb.FileReadResponse{Content: "..."}, nil
}

grpcServer := grpc.NewServer(...)
pb.RegisterSeshatServiceServer(grpcServer, NewSeshatServer(hostConfig))
pb.RegisterFileServiceServer(grpcServer, &FileServer{})

Current Gaps

This is the part that matters if your goal is to complete the gRPC surface rather than just consume it. These are the concrete gaps visible in the current implementation and proto contract.

NameNotesStatus
Proto naming drift in older docsSome repository docs still mention `nexus.proto` or `nexus.NexusService`. The current contract is `pkg/grpc/proto/seshat.proto` and `/seshat.SeshatService/...`.
Interactive permissions`cmd/grpc` forces `sdk.PermissionModeNever`. The surface is intentionally headless and does not provide an approval handshake like the CLI app or a custom host UI could.
Request temperature`QueryRequest.temperature` exists in the proto but is not mapped into `buildSDKClientConfig` yet.
Request stream flag`QueryRequest.stream` is currently redundant. Streaming is selected by calling `QueryStream`.
GetSkillDetails.promptThe proto suggests prompt content can be returned, but the current server only returns skill metadata.
FileService and SystemServiceDeclared in the proto, generated in stubs, but not implemented or registered in `cmd/grpc`.
Health depth`HealthCheck` returns `ok`, version, and uptime; it does not perform a live provider/storage readiness probe per request.
Transport securityNo built-in auth layer and no TLS configuration. Treat it as local or trusted-network infrastructure unless you place it behind your own secure boundary.

The highest-value next steps are straightforward: wire `temperature`, either remove or implement the proto-only services, populate `GetSkillDetails.prompt` if exposing skill bodies is intended, and add a real auth or proxy story if the server is meant to live beyond localhost.