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.
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.
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.
Your host is Go and you want full in-process control over sessions, providers, prompt layers, tools, permissions, hooks, and event handling.
`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.
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.
ANTHROPIC_API_KEY=sk-ant-... SESHAT_MODEL=anthropic:claude-sonnet-4-20250514 go run ./cmd/grpcmake 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
| Name | Notes | Status |
|---|---|---|
| SESHAT_GRPC_PORT | Listening port. Default: `50051`. | — |
| SESHAT_GRPC_MAX_CONCURRENT_RPCS | Mapped to `grpc.MaxConcurrentStreams`. Default: `10`. | — |
| SESHAT_GRPC_KEEPALIVE_TIME | Parsed as a Go duration and used for keepalive enforcement. Default: `30s`. | — |
| SESHAT_GRPC_ENABLE_REFLECTION | Enables gRPC reflection for tools like `grpcurl` without passing the proto explicitly. Default: disabled. | — |
| SESHAT_VERSION | Returned by `HealthCheck` as the server version string. | — |
Shared runtime environment reused by gRPC
| Name | Notes | Status |
|---|---|---|
| SESHAT_MODEL | Default model when the request does not specify one. | — |
| SESHAT_CWD | Working directory inherited by the runtime sessions created behind gRPC. | — |
| SESHAT_DB_PATH | Base runtime SQLite path. Also becomes the default session DB path when `SESHAT_SESSION_DB_PATH` is not set. | — |
| SESHAT_SESSION_DB_PATH | Persistent session store used for `context_id` resume flows. | — |
| SESHAT_PROVIDER_BASE_URL | Useful 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_PATH | Browser runtime settings reused if browser tools are available in the session surface. | — |
| Provider keys | The 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. | — |
`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.
| Name | Type | Behavior | Notes | Status |
|---|---|---|---|---|
| Query | Unary | One request, one final response. | Creates or loads a runtime session, executes one turn, then returns the final assistant text plus usage. | Implemented |
| QueryStream | Server streaming | Streams chunks, runtime events, then a final response. | Best surface for live UIs, logs, or other language SDKs that want incremental output. | Implemented |
| ListSkills | Unary | Lists discovered skills. | Supports source filtering with `all`, `bundled`, `file`, or `mcp`. | Implemented |
| GetSkillDetails | Unary | Returns skill metadata for one skill. | Currently returns the `Skill` metadata only; the `prompt` field in the proto is not populated yet. | Implemented |
| ListMCP | Unary | Lists MCP server statuses. | Returns server name, status, tool count, and last error. | Implemented |
| ConnectMCP | Unary | Registers then reconnects an MCP server. | Supports `stdio`, `http`, `sse`, and `ws`/`websocket`. | Implemented |
| DisconnectMCP | Unary | Disconnects one MCP server. | Only disconnects by name; useful for runtime-controlled extension management. | Implemented |
| GetModels | Unary | Lists models from the provider registry. | This is registry-driven, not only “currently configured” models. | Implemented |
| HealthCheck | Unary | Returns status, version, and uptime. | Current implementation is shallow: it does not re-check downstream providers or storage on every call. | Implemented |
| FileService | Service declared in proto | Read/write/edit/glob/grep surface. | Declared in `seshat.proto` but not implemented or registered in `cmd/grpc`. | Proto only |
| SystemService | Service declared in proto | Bash + 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
| Name | Notes | Status |
|---|---|---|
| prompt | Required. Empty prompts are rejected with `InvalidArgument`. | — |
| model | Optional. Best practice is `provider:model`, for example `anthropic:claude-sonnet-4-20250514` or `codex:gpt-5.3-codex`. | — |
| tools | Optional allowlist. If you pass tools, every other currently-registered tool is unregistered for that session. Unknown tool names return `InvalidArgument`. | — |
| stream | Declared in the proto but currently not used by `cmd/grpc`. In practice, you choose streaming by calling `QueryStream` instead of `Query`. | — |
| context_id | Optional 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. | — |
| temperature | Declared in the proto but currently not wired into `buildSDKClientConfig`. It is a real contract gap today. | — |
| max_tokens | Wired. Overrides host config max output tokens when greater than zero. | — |
| api_key | Per-request credential override. Useful for direct API-key injection and especially for bearer-style Codex / OAuth handoff over gRPC. | — |
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/Querygrpcurl -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
| Name | Notes | Status |
|---|---|---|
| chunk | Carries incremental assistant text in `content` and a structured `chunk` object with `type`, `delta_type`, and `delta`. | — |
| runtime_event | Carries structured engine events such as turn start, tool progress, stop reason, token usage snapshots, and tool metadata. | — |
| final | Carries the final assistant text, `conversation_id`, `stopped`, and final token usage totals. | — |
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/QueryStreamThe 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.
# 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
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
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}")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
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.protoGenerate Python stubs
python -m grpc_tools.protoc -I pkg/grpc/proto --python_out=./gen --grpc_python_out=./gen pkg/grpc/proto/seshat.protoGenerate Node / JS stubs
# 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.
- Edit `pkg/grpc/proto/seshat.proto` and add or change the RPC or message you need.
- Regenerate the Go stubs in `pkg/grpc/seshat/` using `protoc`.
- Implement the server method in `cmd/grpc/main.go` and map it to real runtime behavior instead of placeholder logic.
- If you add a brand new service, register it explicitly on the gRPC server. The proto declaration alone does not expose it.
- Add bufconn-backed integration tests in `cmd/grpc/main_test.go` so request validation, streaming shape, and cleanup behavior stay stable.
- Rebuild, test, and then update docs so transport examples stay aligned with the real contract.
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.
| Name | Notes | Status |
|---|---|---|
| Proto naming drift in older docs | Some 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.prompt | The proto suggests prompt content can be returned, but the current server only returns skill metadata. | — |
| FileService and SystemService | Declared 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 security | No 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.