-
Notifications
You must be signed in to change notification settings - Fork 5
Random notes about service discovery
Chip Morningstar edited this page Apr 16, 2026
·
1 revision
- Who are the actors?
- Service provider
- Service matcher
- Service consumer
- Relay -- necessary component due to libp2p but not part of the model per se
-
Service matcher -- runs on VPS (or anywhere that LLM can run)
- registration interface (running in a vat)
- talking to service providers via ocap messaging
- talking to matching engine using events dispatched by a kernel service
- matching engine (LLM agent managed by harness running in Node?)
- talking to registration interface via event hook handler
- talking to query clients via external NL channel
- registration interface (running in a vat)
-
Service provider -- runs on my laptop
- MetaMask wallet ocap service API (running in a vat)
- talking via kernel service interface to MetaMask wallet (running in a browser plugin)
- Q: is there a non-browser version of this (e.g., Node)? I don't think we need the browser here:
- running as a browser plugin is motivated by:
- sophisticated UX framework
- -> not used here because our UI is CLI/LLM
- convenient delivery platform, leveraging the fact that everybody has a browser
- -> don't care, this is for a specialized audience
- sophisticated UX framework
- running as a browser plugin is motivated by:
- Q: is there a non-browser version of this (e.g., Node)? I don't think we need the browser here:
- talking via ocap messages to service matcher
- registers its address + description(s) of the services it's providing
- talking via kernel service interface to MetaMask wallet (running in a browser plugin)
- Other mock services simulating a service ecosystem, e.g.:
- materials vendor
- parts vendor
- shipping service
- custom 3d printing service
- custom machining service
- custom PC board maker
- custom electronics assembly service
- custom integrated manufacturing service
- working capital finance
- MetaMask wallet ocap service API (running in a vat)
-
Service consumer -- runs on VPS
- human user
- talking to LLM agent via CLI
- using service matching tool (can query for services based on what human says they want)
- talking to service matcher via NL query interface
- using service agent tool (knows what service methods can do from NL descriptions)
- talking to service provider via ocap messages (knows how to invoke service methods from API spec)
- using service matching tool (can query for services based on what human says they want)
- talking to LLM agent via CLI
- human user
-
Relay -- runs on VPS?
- for the various entities that are vat hosted, there needs to be a libp2p relay so they can communicate
- Who are the actors?
- Service matcher -- doesn't exist
- Doesn't exist - service consumer born with hard coded knowledge of provider and just asks for ocap
- Provider responds with the demo ocap regardless of what it was asked for
- Service provider -- runs on my laptop
- MetaMask running in web browser as plugin
- Ocap kernel running inside plugin realizes service API
- Note: regular MetaMask plugin fork with ocap kernel, NOT our test plugin nor omnium-gatherum plugin
- Service consumer -- runs on VPS
- OpenClaw LLM running on VPS
- Ocap kernel running in Node
- LLM talks to ocap kernel via tool that issues queueKernelMessage calls
- LLM has tool that issues queueKernelMessage (?)
- (service consumer) ocap kernel talks to (service provider) ocap kernel via remote message interface
- Relay -- runs on VPS?
- Service matcher -- doesn't exist
- Who are the actors?
- Metamask browser plugin
- Installed into browser on "home" laptop
- Creates a group of specialized exos and registers them as kernel service objects:
-
hostApiProxy- Has a single method,
invoke(method: string, args: unknown[]): unknown- invokes an operation provided by the browser plugin itself, described by
methodCatalog - operations used directly are:
-
OcapKernelController:setCapabilityVendorURL- tells the plugin the ocap URL for the VPF
AccountsController:listAccountsNetworkController:findNetworkClientIdByChainIdSignatureController:newUnsignedPersonalMessage
-
- invokes an operation provided by the browser plugin itself, described by
- Has a single method,
-
methodCatalog(DOES NOT APPEAR TO BE USED)- Maintains a catalog of methods invocable via hostApiProxy.invoke
- Initialized from a static JSON
- file
metamask-extension/app/offscreen/ocap-kernel/services/method-catalog-data.json - encodes an array of
MethodEntryobjects, each having:-
name-- string of the form${controller}:${method}, used for invocation -
signature-- TypeScript method signature string -
description-- NL plaintext description
-
- file
- Provides methods:
-
getAllMethods(): MethodEntry[]- returns all the entries in the catalog
-
getControllers(): string[]- returns the controller strings
-
getMethodsByController(controller: string): string[]- returns the methods with a given controller
-
search(query: string): MethodEntry[]- returns all entries whose name or description matches
queryin the stupidest way
- returns all entries whose name or description matches
-
-
llmService- Simulates an LLM that you can prompt, provides a single method:
-
prompt(request: string): LlmResponse- Returns a data object:
- capabilityName: string,
- sourceCode: string,
- description: string,
- methodNames: string[]
- Simulated response is a single static object with
- capabilityName: 'PersonalMessageSigner',
- sourceCode: JavaScript source for an exo with
getAccountsandsignMessagemethods - description: a doc string for the same,
- methodNames:
['getAccounts', 'signMessage']
- Returns a data object:
- The source code given in the
sourceCodeproperty seems to be real, and simulates the LLM being- asked for information about a service to sign messages
-
- Simulates an LLM that you can prompt, provides a single method:
-
- Creates ocap "home" kernel
- Connects automatically to relay indicated by env var containing relay libp2p multiaddr
- Loads a single vat cluster containing the
capability-vendorvat- code in
metamask-extension/app/offscreen/ocap-kernel/vats/capability-vendor/index.ts - creates an internal object "VPF" typed as a
vendorPublicFacetwith method:-
requestCapability(request: string): CapabilityRecord- passes the request string to the
llmService.promptmethod and then passes the result of that to an invocation ofApprovalController:addRequestvia hostApiProxy.invoke to get the user's approval (which will include an echo of the service description properties from the llm) - assuming it gets the approval, passes the sourceCode value to evaluate (in a compartment) and captures the result of that (an exo)
- uses the exo and the other llm provided info (via the approval result) to populate a CapabilityRecord
- returns "the" CapabilityRecord
- passes the request string to the
-
- stashes VPF descriptive record in internal
capabilitiesmap key by id (in this case 0) - creates root object typed as a
vendorAdminwith methods:-
bootstrap(<the usual>)- sets things up in the usual way
- returns the VPF ocap url
-
getPublicFacet(): vendorPublicFacet- returns a reference to the VPF
- other (vestigial?) methods that are not relevant here
-
- code in
- Takes the bootstrap result (which is the VPF ocap URL) and gives it to the plugin via hostApiProxy object's
invokemethod, invokingOcapKernelController:setCapabilityVendorURL
- Relay
- A regular libp2p relay, running on the VPS
- Ocap daemon
- Node process loads ocap "away" kernel
- No vats -- the kernel acts directly on requests for kernel-level services delivered via rpc
- The kernel exposes key services via the rpc interface:
- redeem-url
- redeems ocap URL resulting in a kernel object (koXX) in the "away" kernel
- this will generally involve talking via the relay to other kernels, notably the "home" kernel
- redeems ocap URL resulting in a kernel object (koXX) in the "away" kernel
- queueMessage
- enqueues an arbitary captp message to a kernel object onto the "way" kernel's run queue
- the kernel will deliver this to either a local vat or a remote kernel
- in the current demo, this will be an object in the "home" kernel reachable via the relay
- the kernel will deliver this to either a local vat or a remote kernel
- enqueues an arbitary captp message to a kernel object onto the "way" kernel's run queue
- exec
- executes an arbitrary operation on an arbitrary kernel rpc entry point
- the kernel exposes all kinds of functionality this way
- this operation is extremely hazardous and should only be used for debugging purposes
- executes an arbitrary operation on an arbitrary kernel rpc entry point
- redeem-url
- The kernel exposes key services via the rpc interface:
- No vats -- the kernel acts directly on requests for kernel-level services delivered via rpc
- Node process loads ocap "away" kernel
- Demo...
- in Manual mode: the human enters CLI commands of the form
yarn ocap daemon ...- the ocap CLI app:
- synthesizes rpc messages based on command line params
- transmits them to the daemon process via the rpc socket it exposes
- the daemon process parses these, feeds them to the kernel, serializes the result, and returns it
- awaits the result and then prints it out
- the ocap CLI app:
- in LLM mode: the human types NL requests at the OpenClaw LLM harness
- an OpenClaw plugin gives the LLM a tool it can use to talk to the daemon process as the CLI app would
- in either mode (described here in terms of CLI operations, but LLM does the same thing)
-
- extract ocap url from MetaMask plugin UI -->
-
- yarn ocap daemon redeem-url -->
-
- yarn ocap daemon queueMessage requestCapability '["view user accounts"]'
- approve request at MetaMask plugin prompt
- --> JSON info, including and method names 'getAccounts' and 'signMessage' and copy of source code from llm info above
- yarn ocap daemon queueMessage requestCapability '["view user accounts"]'
-
- yarn ocap daemon queueMessage ko5 getAccounts --> JSON info, including
-
- yarn ocap daemon queueMessage ko5 signMessage '["", "YOUR MESSAGE", "0x1"]'
- confirm signing at MetaMask plugin prompt
- --> ""
- yarn ocap daemon queueMessage ko5 signMessage '["", "YOUR MESSAGE", "0x1"]'
-
- in Manual mode: the human enters CLI commands of the form
- Metamask browser plugin
- MetaMask plugin
offscreen.ts:initcallsoffscreen/ocap-kernel/index.ts:runKernel -
runKernelcreates:- (a) hostApiProxy kernel service exo
- (b) llmService kernel service exo
- (c) kernel with single vat subcluster containing the 'vendor' vat (which is the bootstrap vat)
- vat defined by
:buildRootObject
- vat defined by
-
buildRootObjectcreates:- (d) 'vendorPublicFacet' exo (stored) "VPF"
- (e) 'vendorAdmin' exo (returned as vat root) "VA"
-
VA.bootstrapreturns ocap URL for VPF, which runKernel gives to plugin for revelation to user - user obtains VPF ocap URL from plugin UI
- user agent redeems VPF ocap URL and receives VPF reference
- user agent sends
requestCapabilitymessage to VPF -
VPF.requestCapabilitycallsllmService.prompt -
llmService.promptreturns staticLlmResponseobject "LLMR" -
VPF.requestCapabilitycallshostApiProxy.invoke::ApprovalController:addRequestwith LLMR contents -
ApprovalController:addRequestprompts for user approval, returnsCapabilityApprovalResultwith LLMR contents -
VPF.requestCapabilitycreates Compartment endowed withhostApiProxy- (f)
'PersonalMessageSigner'by evaluatingLLMR.sourceCodeinCompartment("PMS")
- (f)
-
VPF.requestCapabilityreturnsCapabilityRecordcontaining ref to PMS - user agent sends
getAccountsmessage to PMS -
PMS.getAccountscallshostApiProxy.invoke::AccountsController:listAccountsand returns result from that -
AccountsController:listAccountsreturns record includingchainAddress -
PMS.getAccountsreturns this record to user - user agent sends
signMessagewithchainAddress,messageToSign, andchainIdto PMS -
PMS.signMessagecallshostApiProxy.invoke::NetworkController:findNetworkClientByChainIdwithchainIdto getnetworkClientId -
PMS.signMessagecallshostApiProxy.invoke::SignatureController:newUnsignedPersonalMessagewithchainAddress,messageToSign, andnetworkClientIdto getsignedMessage -
PMS.signMessagereturnssignedMessageto user
- (All in
metamask-extension/app/offscreen/ocap-kernel - (a)
hostApiProxykernel service:services/host-api-proxy.ts - (b)
llmServicekernel service:services/llm-service.ts - (d) capability vendor vat root VA:
vats/capability-vendor/index.ts- (return value from
buildRootObject)
- (return value from
- (e) capability vendor public facet VPF:
ocap-kernel/vats/capability-vendor/index.ts- (return value from
bootstrap)
- (return value from
- (f)
'PersonalMessageSigner'"PMS":services/llm-service.ts- (JS source inside literal string property of static result object returned from
prompt)
- (JS source inside literal string property of static result object returned from
- The status quo vs. the idealized model
- In the demo, there is basically one service,
signMessage - Service provider
- The service provider is the PMS object
- calling the
hostApiProxykernel service- calling the plugin's
NetworkControllerandSignatureControllerobjects to actually do the work
- calling the plugin's
- executing inside the
'vendor'vat- executing inside the "home" kernel
- executing inside the MetaMask browser plugin
- executing inside the "home" kernel
- PMS definition is funky:
- specified by the
llmServicequery response as if it were describing something there but actually it's created by evaluating a string in the query response struct
- specified by the
- calling the
- The service provider is the PMS object
- Service matcher
- There is no component corresponding to the service matcher as such
- The VPF conflates the roles of service matcher and service contact point
- The service consumer sends
requestCapabilityto the VPF with a NL query string- This provides the service matcher function, sort of
- In the fantasy the demo is pretending to be, this query string is interpreted by an LLM
- In reality, it gives a canned response that is the same regardless of the query
- This response is a description of the signMesage service
- This provides the contact point function, sort of
- MetaMask browser user must approve the vending of the service capability
- The user is given information about the service itself, not the use
- Not totally crazy: what they're really authorizing is PMS's use of the
hostApiProxy
- Not totally crazy: what they're really authorizing is PMS's use of the
- The user is given information about the service itself, not the use
- MetaMask browser user must approve the vending of the service capability
- This provides the service matcher function, sort of
- The service consumer sends
- Service consumer
- LLM mode demo closely resembles the intended end state, except:
- Has to interact with the demo service provider & sort of matcher functionalities as they are
- Doesn't actually benefit from having an LLM on the matching side
- Doesn't try to reason about what API it is seeking based on vague mission statement
- LLM reasoning is mostly about flexibility in how to consume a well understood functionality
- LLM mode demo closely resembles the intended end state, except:
- In the demo, there is basically one service,