Underneath every Seed site and every Seed app is one process, the Seed daemon. It holds the blobs, indexes them, syncs with peers, and answers a gRPC API. The web server, the desktop app and the CLI's local development mode are all clients of that API.
Most builders never need it. The Seed API over HTTP and the SDK cover reading, searching and publishing, and they work against any site on the network without running anything. Use gRPC when you run a daemon yourself and want what only it can do: manage keys, subscribe to spaces, drive sync and discovery, list peers, or query the index in ways the HTTP keys do not expose.
Connecting
The daemon listens on three ports. Which numbers depends on who started it.
Listener | Daemon default | Seed desktop app | Dev build of the app | Site container |
|---|---|---|---|---|
HTTP, with gRPC-Web at |
|
|
|
|
plain gRPC |
|
|
|
|
libp2p |
|
|
|
|
Flags are -http.port, -grpc.port and -p2p.port. Every flag can also be an environment variable with the SEED_ prefix, so -http.port is SEED_HTTP_PORT. The full flag list is on the daemon page.
The plain gRPC port speaks standard gRPC with server reflection enabled, so grpcurl can explore it without the proto files. Against a running desktop app:
grpcurl -plaintext localhost:56002 listcom.seed.activity.v1alpha.ActivityFeed
com.seed.activity.v1alpha.Subscriptions
com.seed.daemon.v1alpha.Daemon
com.seed.documents.v3alpha.AccessControl
com.seed.documents.v3alpha.Comments
com.seed.documents.v3alpha.Documents
com.seed.documents.v3alpha.Resources
com.seed.entities.v1alpha.Entities
com.seed.networking.v1alpha.Networking
com.seed.p2p.v1alpha.P2P
com.seed.p2p.v1alpha.Syncing
com.seed.payments.v1alpha.Invoices
com.seed.payments.v1alpha.Wallets
com.seed.telemetry.v1alpha.Telemetry
grpc.reflection.v1.ServerReflection
grpc.reflection.v1alpha.ServerReflectiongrpcurl -plaintext localhost:56002 com.seed.daemon.v1alpha.Daemon/GetInfo{
"state": "ACTIVE",
"peerId": "12D3KooWGZRLjYnJpZUQBFYu5qUqPK2rW2rA62GtdRSXGw6KvExz",
"startTime": "2026-09-16T18:15:28.665346Z",
"protocolId": "/hypermedia/0.9.2"
}grpcurl … describe com.seed.documents.v3alpha.Documents prints a service's RPCs and message types. The HTTP port carries the same services as gRPC-Web, which is what the browser-based clients use. The desktop app and the web server both connect with @connectrpc/connect transports to the HTTP port, never to the raw gRPC port. The daemon also embeds a grpcui at http://localhost:<http-port>/debug/grpcui/, protected by the same admission policy as the ordinary API.
Message definitions live in the repository under proto/, one folder per service family, and generated clients are committed beside them: Go under backend/genproto and TypeScript under frontend/packages/shared/src/client/.generated. The TypeScript package exposes createGRPCClient(transport) with one property per service. After editing a proto file, ./dev gen regenerates both.
API admission and trust
In default mode, the daemon admits only loopback socket peers to its gRPC and HTTP APIs. Once admitted, a local tool is trusted: it can list keys, sign arbitrary bytes with stored keys, export or delete keys, store blobs, create refs and capabilities, force a reindex, and read everything the daemon holds. HTTP requires the Host hostname to be exactly localhost or a literal loopback IP and checks browser fetch metadata and exact origins. -api.allowed-origins registers additional trusted origins, including the desktop renderer's, without widening peer or Host admission.
Write RPCs check the signing key. Every write takes a signing_key_name. The daemon loads that key from its own store and checks that it may write to the target space and path. It never asks whether the caller may write. Comments skip even that check: anyone may comment on anything.
Daemon.Authenticate proves possession of an account key and returns a bearer token valid for thirty days. The HTTP middleware accepts it as Authorization: Bearer <token>. In server mode (-server-mode or SEED_SERVER_MODE=true), private content is hidden from anonymous requests and shown to authorized bearer callers. In default mode, admitted callers already have full read access. The plain gRPC port ignores the bearer token.
Server mode trusts the deployment network and bypasses default-mode ingress checks. A site's daemon publishes only its libp2p port outside the container network; its HTTP and gRPC API ports stay private, reachable by trusted deployment services, and the reverse proxy forwards only /ipfs/* to it. The Docker image enables this mode through SEED_SERVER_MODE=true, even when Compose passes no mode flag. Keep both API ports behind a firewall or on a private interface. Integrity puts this in the larger trust model.
Conventions
Addressing. A space is named by its account, the principal string of its key. A document is account plus path, where the empty path is the home document. A version is one or more Change ids joined by .. An empty version means latest. Comments and contacts are addressed as <author>/<tsid>. The proto files still say account where the rest of the documentation says space. A rename is on the backend team's list.
Pagination. Requests take page_size and page_token. Responses return next_page_token. Tokens are opaque cursors. A page size of zero or less means the handler's default, which differs by RPC between 10 and 100. Document listings cap larger requests at 2000. Some listings ignore paging and return everything. They are marked below.
Redirects. GetDocument on a path that holds a redirect Ref fails with FailedPrecondition and attaches RedirectErrorDetails {target_account, target_path, republish} to the status. GetDocumentInfo returns the redirect as data instead of failing. Follow redirects with a cycle guard.
Status codes.
Code | Meaning in this API |
|---|---|
| unparsable principal, id, version or page token; a missing required field |
| unknown key name, document, version or tracked domain |
| the path holds a redirect; a Ref with a different genesis and no higher generation; discovery disabled; vault not connected |
| the signing key may not write there; unauthorized private read in server mode; a capability whose signer is not the account |
| a bearer token that is malformed, expired or unknown (HTTP |
|
|
| see the catalogue |
| storage failures and recovered panics |
Service catalogue
The daemon registers fourteen services, plus gRPC reflection. Each table lists every RPC with one line. Unimplemented RPCs still appear in the proto files and in reflection. Calling them returns Unimplemented.
Daemon
Node management, keys, authentication, the vault connection, and the domain tracker.
RPC | What it does |
|---|---|
| state ( |
| a fresh BIP-39 phrase, 12 words by default; stateless |
| derive a key from a mnemonic and store it under a name; the empty name becomes the public key string |
| load a |
| write a key file, optionally password-encrypted, to an absolute path on the daemon's filesystem |
| list, rename, delete; |
| sign arbitrary bytes with any stored key |
| store blobs atomically; a given |
| prove an account key and receive a thirty-day bearer token; the principal must already appear in some blob the daemon holds |
| rebuild every derived table from the stored blobs, synchronously |
| Unimplemented |
| the connection between this daemon and a remote vault that holds the user's keys; see identity |
| the tracker that polls |
Documents
The document model: reading, preparing changes, refs, accounts, profiles, contacts, listings and attribute queries. The proto file itself warns that this service is a kitchen sink.
RPC | What it does |
|---|---|
| a document at a version or latest; fails with redirect details on a redirect path |
| metadata, authors, breadcrumbs, activity summary, generation and redirect info, without the body |
| build an unsigned Change from edit operations against a base version; the client signs it and calls |
| Unimplemented; publish a tombstone Ref with |
| publish a version, tombstone or redirect Ref signed by a named key; timestamps round to milliseconds; a different genesis needs a higher generation. |
| accounts known to this node with their home document info, profile and alias |
| publish a Profile blob; the key must write the space root |
| link this key to another account; needs an AGENT capability |
| contact records; |
| children of a path, optionally recursive, with sort options |
| all documents, home documents, or documents whose parent does not link to them |
| filter by attributes, path, space and URL with and/or/not, sorted by built-in or user attributes; the query grammar |
| which attribute keys exist and which values a key takes, for autocomplete |
| the change history of a document and one change's author, deps and time |
| local read or unread state, never published |
AccessControl
RPC | What it does |
|---|---|
| capabilities that apply to a space and path; |
| capabilities granted to one principal |
| sign a capability delegating |
| one capability by id |
There is no RevokeCapability. Permissions explains what that means in practice.
Comments
RPC | What it does |
|---|---|
| publish a comment on a document version, optionally as a reply; visibility is inherited from the target at creation. Passing |
| by record id |
| every comment on a document; paging parameters are ignored |
| comments by one account |
| replace a comment with a full new snapshot |
| the signing key must be the author |
| reply count; every version of one comment, newest first |
Resources
RPC | What it does |
|---|---|
| resolve an |
| who links to, embeds or mentions a resource, in the order this node learned of them |
| announce documents to a specific peer and stream progress; what the desktop calls to publish to a site |
Entities
RPC | What it does |
|---|---|
| ask the network for a document, a subtree ( |
| full-text search over documents, comments and contacts with filters, plus semantic and hybrid modes when an embedding model is configured |
| deprecated; use |
| Unimplemented |
ActivityFeed and Subscriptions
RPC | What it does |
|---|---|
| new blobs and mentions this node has seen, filtered by author, event type or resource, ordered by claimed or observed time |
| subscribe to a space or path so the node keeps it synced; also triggers discovery and, unless |
| stop |
| everything subscribed; paging ignored |
Networking
RPC | What it does |
|---|---|
| a peer's addresses, connection status and account binding |
| known peers without their addresses; call |
| dial a multiaddr or a bare peer id now |
P2P and Syncing, the peer protocol
These are the RPCs peers exchange over libp2p. The network page explains the protocol. The daemon also re-exports them on its local gRPC server as a proxy: attach a target-peer metadata key holding a peer id, and the call is forwarded to that peer. This is how you inspect what another node offers.
RPC | What it does |
|---|---|
| stream the ids of every public blob, from a cursor |
| peer exchange and the spaces a node holds |
| prove an account key to a peer for this connection, which gives access to that account's private blobs |
| Lightning invoice; |
| range-based set reconciliation of blob sets per scope |
| the receiving end of a push |
Wallets and Invoices
Lightning wallets through a hosted lndhub at ln.seed.hyper.media (or the testnet host without -lndhub.mainnet): CreateWallet, ImportWallet, ExportWallet, RemoveWallet, ListWallets, GetWallet, GetWalletBalance, UpdateWalletName, GetDefaultWallet, SetDefaultWallet; CreateInvoice, PayInvoice, DecodeInvoice, ListPaidInvoices, ListReceivedInvoices. An LNURL service exists in the proto files but is never registered.
Telemetry
RecordCheckpoints appends client-side timing checkpoints to an in-memory buffer shown on the daemon's /debug/journeys page. It shares the ordinary API admission policy rather than a separate service-specific gate.
The daemon's own HTTP routes
Besides gRPC-Web, the HTTP port serves a few plain routes. They all share the API admission policy: local tools, same-origin browsers and explicitly trusted callers in default mode; trusted deployment networking in server mode.
Route | Purpose |
|---|---|
| bytes of a blob or file, with range support; searches the network for up to a minute when unknown |
| a structural blob decoded to DAG-JSON |
| multipart |
| store one raw block whose hash must match |
|
|
|
|
| completes a browser-mediated vault connection with a short-lived token |
| operator pages, local only |
Working with it
In the Seed app
The desktop app is a gRPC-Web client of its bundled daemon on port 56001. You can open http://localhost:56001/debug/grpcui/ in a browser on the same machine and call any RPC by hand.
CLI
The Seed CLI signs locally and talks to a site's Seed API. The one exception is seed-cli space dev, which registers its dev key in the desktop dev app's daemon over gRPC-Web (--daemon, default http://localhost:58001) and publishes through the app's HTTP bridge. For raw daemon calls use grpcurl as above.
SDK
@seed-hypermedia/client has no gRPC dependency by design, so it runs in browsers, Bun, Node and React Native. When you need the daemon, take the generated TypeScript clients from the shared package in the repository and a gRPC-Web transport pointed at the HTTP port. The desktop app and seed-cli space dev use @connectrpc/connect-web, and the web server uses @connectrpc/connect-node.
Agents
Seed Agents run beside a site and use the Seed API. They do not use gRPC. An external agent on a machine with a daemon can use grpcurl from its shell. It can fully control any daemon it can reach, which is one more reason to keep daemon ports off the network.
See also
Seed API, the HTTP surface built on top of these services
Daemon, flags, data directory and how the apps launch it
Network, what the P2P and Syncing services do between peers
Integrity, the trust model and its limits
Contributing, regenerating clients after a proto change
SDK, the client that needs no daemon
Do you like what you are reading? Subscribe to receive updates.
Unsubscribe anytime