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.
/rpc/uno.kit.v1.SigningService/FinalizeWriteThe 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
Request Body
Responses
stringThe durable job identity. Client-signed jobs continue through next_record and FinalizeWrite.
objectThe next frozen group, returned only after this object landed. Each group requires its own signature. Absence means the write finished.
string | nullImmutable expiry of the grant applied by this publication, in Unix seconds.
stringThe status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
canceledunknowninvalid_argumentdeadline_exceedednot_foundstringA developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.
Freezes one unsigned object for the caller to sign.
/rpc/uno.kit.v1.SigningService/PrepareWriteThe 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
Request Body
application/jsonstringThe 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.
Responses
stringThe status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
canceledunknowninvalid_argumentdeadline_exceedednot_foundstringA developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.