Skip to content
Uno Docs

SigningService

SigningService runs the client-signing flow of the caller's namespace: a write that a self-owned key of the owner signs, instead of the custodial key. A write that asks for no client signature stays custodial: StagingService.Commit, KitService.Tag and KitService.Remix do not change, and there is no silent fallback between the two.

The flow is prepare, sign, finalize:

  • PrepareWrite names the write and the self-owned key. The engine selects the fields of the unsigned object: the tree of the session or of the target, the parents, the message and the time. The control plane freezes them in a prepare record owned by the caller, and answers with them.
  • The client rebuilds the object and its signing bytes locally, checks the fields against its own staged content, and signs the bytes with the key.
  • FinalizeWrite takes the signature and the key id. The caller must still have write access, the record must be live and matching, the expected head must still hold, and the key must be active. The engine rebuilds the object from the record, verifies the signature against the keyring, and pushes one signed group. Its answer can carry the next frozen group. Each group requires its own signature.

The record binds the owner, the repo and the ref, the expected head, the staged content, the kind and the exact fields, the key, the authority generation and the expiry. A signature that matches no record signs nothing, and a payload that differs from the record is not a retry.

The Uno CLI exposes client signing. HTTP MCP writes remain custodial; this service runs on the Kit control plane.

Conventions and error codes: see common.proto.

Pushes the object that the signature covers.

POST/rpc/uno.kit.v1.SigningService/FinalizeWrite

The record is the idempotency store, so this RPC takes no idempotency_key. A repeat of the same prepare_id, key_id and signature returns the recorded answer. A different payload on the same record fails with invalid_argument.

Codes: already_exists, failed_precondition, invalid_argument, not_found, unauthenticated, unavailable, unimplemented.

Header Parameters

Connect-Protocol-Version
number·const 1

Define the version of the Connect protocol

Example1
Connect-Timeout-Ms
number

Define the timeout, in ms

Example1000

Request Body

application/json
prepareId
string

The record to finalize.

keyId
string

The key that signed. It must be the record's key.

signature
string

The Ed25519 signature over the kit signing bytes of the object that record.fields builds: 128 lowercase hex characters.

Responses

Freezes one unsigned object for the caller to sign.

POST/rpc/uno.kit.v1.SigningService/PrepareWrite

The answer carries the record: its fields are the unsigned object. A commit prepares the write of a staging session; a tag or a remix names its repo. A repeat with the same idempotency_key and the same request returns the record. A used idempotency_key with a different request fails with invalid_argument.

Codes: invalid_argument, failed_precondition, not_found, resource_exhausted, unauthenticated, unavailable, unimplemented.

Header Parameters

Connect-Protocol-Version
number·const 1

Define the version of the Connect protocol

Example1
Connect-Timeout-Ms
number

Define the timeout, in ms

Example1000

Request Body

application/json
keyId
string

The self-owned key that signs: "key:" and a UUIDv7. The key must be active in the caller's keyring; a custodial key cannot sign here.

idempotencyKey
string
commit
object

A commit to prepare: the write of a staging session.

tag
object

A tag to prepare.

remix
object

A remix to prepare: a repo copied from a source commit.

Responses