RPC method families for gateway status and identity, models and usage, channels and login, plugin management, messaging and logs, and the operator terminal.

System and identity

Models and usage

Memory

These methods require authenticated operator read authority. memory.get and memory.status use the provider-runtime contract directly; memory.search selects that contract when version: 2 is present.

Channels and login helpers

Channel DM pairing

channels.pairing.list, channels.pairing.approve, and channels.pairing.dismiss manage channel DM access requests. They are separate from device bootstrap.

The existing list request accepts optional channel and accountId and returns accounts, requests, commandOwnerConfigured, and limits. Public request rows contain a requestId and sender/account metadata, never the pairing code. Existing approval and dismissal use channel, accountId, and requestId; approval also accepts notify and bootstrapCommandOwner. Approval returns requestId, senderId, notification, and commandOwnerBootstrap; dismissal returns requestId and senderId. These contracts remain unchanged.

The local CLI uses two explicit, operator.admin-protected branches after negotiating the corresponding owner capability:

Method Request Result
channels.pairing.list format: "cli", channel, expectedOwnerId; optional accountId Raw request array containing id, code, createdAt, lastSeenAt, and optional meta.
channels.pairing.approve channel, code, expectedOwnerId; optional accountId { id, entry }, where entry is the raw approved request, or null when no pending code matches.

The code selector and existing request-ID selector are mutually exclusive. Omitting accountId in the CLI branch preserves cross-account listing and code lookup; an explicit account restricts both. The owner resolves and mutates the matching request. CLI output remains unchanged, and first-command-owner config bootstrap and optional notification remain client-side after acknowledgement. Neither runs after a refusal or unknown outcome. Listing is mutation-capable because it prunes expired or excess pending requests.

Plugin management

Catalog detail and client confirmation

detail.downloadability has one of these shapes:

Status Meaning
{ "status": "downloadable" } The source has confirmed selected-release artifact availability.
{ "status": "unavailable", "reason": "..." } A missing release or source download policy prevents download.
{ "status": "unknown", "reason": "..." } The source cannot establish availability, or the registry read failed.

ClawHub currently exposes a selected plugin release's download-policy block, but its read-only detail and artifact resolver do not check stored artifact bytes. A permitted security verdict, download URL, listing, or local install action therefore produces unknown, never downloadable. A side-effect-free per-release availability fact requires a ClawHub contract extension. Gateway inspection does not download packages to check them; registry download routes record telemetry.

A native client can fetch plugins.catalog.get, inspect the same catalogId, display the returned facts, and collect confirmation itself. After approval, call plugins.install with source: "clawhub", the exact returned packageName, and selectedRelease.version when present. Preserve scope and publisher spelling; do not rebuild the package name from a runtime plugin ID. If installation requires capability consent or install-policy acknowledgment, display that owner-issued review and retry the same intent with its acknowledgment. Catalog inspection does not grant consent or bypass install policy, integrity, trust, or authorization. Cancel sends no installation RPC. The Gateway does not manage confirmation dialogs.

Runtime-only refresh works with read-only, Nix-managed, and root $include configurations without rewriting them. Plugin lifecycle and Claw package removal requests return retryable UNAVAILABLE with retryAfterMs when another plugin or config operation is already applying. This busy response occurs before the requested mutation starts; retry after the current operation completes. Failures after a mutation starts retain their application details and are not automatically retryable.

These mutations wait for runtime application without restarting the Gateway. Successful responses include restartRequired and a runtime receipt with operationId, generation, pluginIds, and optional sourceDigests. Reloading unchanged bundled code or replacing captured external code returns restartRequired: false; edited bundled code that remains loaded, or whose files cannot be verified, requires a restart. The Gateway broadcasts plugins.changed with { generation } after publication. Runtime replacement errors include details.runtime.phase and details.runtime.committed, so clients can distinguish rejection before publication from failure after a new generation became active.

If a multi-step mutation publishes a runtime and later fails, details.runtime retains the published receipt with committed: true. A subsequent replacement that fails before publication is reported separately in details.runtimeAttempt. Clients should refresh their runtime view after any committed change, even when the overall mutation fails.

An install error can also include details.persistence: { operation: "install", pluginId }. This records that installation was saved, independently of runtime publication. Refresh the installed inventory and config; fix the reported problem and reload the installed plugin instead of blindly repeating installation. details.runtime.committed: false does not mean the installation was rolled back.

Install, enable, and reload may require capability consent. After reviewing the declared capabilities, pass acknowledgeCapabilities: { reviewToken }; the token is checked against a fresh inspection before application. This is separate from install-policy warning approval. See Plugin management.

Reload preconditions are optional. installHash is the lowercase SHA-256 of the canonical saved install record and requires a tracked package. sourceDigests maps resolved runtime plugin IDs to lowercase SHA-256 source digests. Tracked targets resolve their entire package; a bundled or configured source without an install record resolves its discovered runtime ID. Ambiguous, missing, or conflicting managed ownership still rejects the request. The Gateway checks target ownership and expected records before and after consent, then validates source expectations against the captured code it loads. Consent can update the saved install record: if that changes a supplied installHash, reload fails visibly without publishing runtime. The caller must refresh its expected state before retrying; the Gateway never rewrites the supplied hash. An acknowledgment covers its reviewed declared surface, and a different required surface stops the operation before runtime publication. Reload does not rebuild compiled bundled code or grant file-mutation authority.

sourceDigests requires a captured-source plugin instance and Node's synchronous module hooks. Runtimes without those hooks, including Bun 1.4.2, omit these digests and reject requests that supply them. Ordinary Bun reloads capture fresh source for the replacement while retaining the old instance for admitted consumers; see runtime instance and source lifetime.

ClawHub catalog discovery

catalog.browse and catalog.searchKeywords require operator.read. Clients check hello-ok.features.methods before using them; older Gateways continue to expose the existing plugin and skill RPCs. All registry requests run on the Gateway, including when it runs remotely or inside WSL.

Browse and search

Call catalog.browse with these fields:

Field Contract
kind Required: plugin or skill. Results stay within that kind.
query Optional text, at most 200 characters. Whitespace-only text means browse.
feed catalog (default) or trending. Search cannot select trending.
officialOnly Optional boolean, default false. The Gateway excludes any listing without an explicit official flag.
pageSize Integer from 1 to 100, default 20.
cursor Opaque continuation from the same kind, feed, and filter request. Search does not accept a cursor.
agentId Selects the skill workspace. Omit only when the Gateway can select an agent unambiguously. Plugin discovery does not need an agent.

For example:

{
  "kind": "skill",
  "officialOnly": true,
  "pageSize": 20,
  "agentId": "main"
}

The response contains items and mode (catalog, trending, or search). Catalog and trending pages can return nextCursor. Filtering can produce an empty page with a continuation; continue while that cursor exists. Full catalog browsing uses the registry's paginated plugin and native skill catalogs. Trending is a bounded ranking feed, not the complete catalog. The existing initial plugins.catalog.browse overview retains its bounded behavior.

Text search returns at most searchLimit upstream candidates, equal to the requested page size. Official filtering can reduce that count. Upstream search has no continuation, so it cannot promise every possible matching listing. A successful empty response means no qualifying listings were returned. remoteError means registry discovery failed; any returned cursor repeats the input cursor so the client can retry the same page. Installation-status failure returns UNAVAILABLE instead of claiming that listings are uninstalled.

Each item has kind, registry, id, catalog metadata, and local facts. Treat (kind, registry, id) as its canonical identity. Plugin IDs preserve the existing ch_... discovery identity, so plugins.catalog.get can open details; catalog.packageName supplies the existing plugin installation locator. Skill IDs equal installRef: native @publisher/slug or a source-qualified external reference. Pass installRef unchanged as slug to existing skill lifecycle RPCs. Respect installOnly; those entries have no ordinary skill detail card. The companion listing detail workstream does not change these identities.

Skill local facts include the resolved agentId, installed, enabled, eligible, and, when installed, skillKey. They come from the selected workspace's existing status reader and valid tracked registry/source/publisher identity. A matching display name or bare slug does not establish installation. Plugin local facts reuse the existing managed inventory and mutation policy. Neither operation installs anything or changes approval requirements.

Bulk keyword discovery

Call catalog.searchKeywords with keywords (1–100 nonblank strings, each at most 200 characters), optional kinds (plugin, skill, or both; default both), agentId, pageSize (1–100, default 20), and an optional returned cursor. The Gateway trims and collapses whitespace, lowercases and deduplicates terms, and searches each individual term for each selected kind. It always returns only official listings, deduplicated by canonical identity, in deterministic identity order. It never concatenates the terms or interprets application inventories. Clients own application detection and keyword generation.

The response contains the normalized keywords, items, searchLimit: 100, errors (each with kind, query, and message), and optional nextCursor. The cursor pages the complete union of those bounded searches; no matches within that union are silently dropped. The upstream 100-candidate limit still applies to each term and kind, so this is not an exhaustive registry search. An empty union with no errors differs from an empty or partial union with failed queries. Retry a request with errors to recover failed terms.

Bulk continuation re-reads the same bounded searches with at most four searches in flight, without retaining a second inventory. Cursors bind the normalized terms, kinds, registry, selected workspace, and result identities. If the matches change, the Gateway returns INVALID_REQUEST with a restart instruction rather than silently skipping results. Large keyword sets and subsequent pages perform more registry reads than ordinary searches; clients should allow a longer RPC request timeout and retain the original request for retries.

Upstream contracts and gaps

Native skill catalog browsing and search use ClawHub's existing /api/v1/packages?family=skill and /api/v1/packages/search?family=skill contracts. These project the native skill catalog and expose the listing's isOfficial flag. /api/v1/skills currently omits that flag. Canonical skill search and trending can combine publisher and listing official status; the new catalog does not use publisher official status as a substitute. Native trending entries therefore read their listing flag from package metadata in bounded batches. The package-detail route can resolve a same-named package first; its metadata qualifies only when family, slug, and publisher match the exact skill. Mismatched metadata leaves official status unknown. Missing flags never qualify; featured status, verification tiers, publisher handles, and bundled provenance cannot qualify a listing either.

The package skill catalog currently covers native ClawHub skills. External sources can appear in the canonical trending feed with their original install-only identities, but currently expose no separate listing-level official flag and cannot qualify for official suggestions. Existing skills.search retains its canonical cross-source search and omitted-query trending behavior; its public result contract also declares the existing optional official field. No cross-kind category taxonomy or global relevance ranking is introduced.

Messaging and logs

Operator terminal