<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>Terracrypt</title><id>https://www.terracrypt.net/feeds/tags/guile.xml</id><subtitle>Tag: guile</subtitle><updated>2026-03-01T20:46:16Z</updated><link href="https://www.terracrypt.net/feeds/tags/guile.xml" rel="self" /><link href="https://www.terracrypt.net" /><entry><title>Adding persistence to gobs-of-machines</title><id>https://www.terracrypt.net/posts/gobs-of-persistence.html</id><author><name>Jonathan Frederickson</name><email>jonathan@terracrypt.net</email></author><updated>2025-02-14T13:16:00Z</updated><link href="https://www.terracrypt.net/posts/gobs-of-persistence.html" rel="alternate" /><content type="html">&lt;p&gt;A couple updates on the &lt;a href=&quot;/posts/gobs-of-machines.html&quot;&gt;gobs-of-machines&lt;/a&gt; work from a while back!&lt;/p&gt;&lt;p&gt;The smaller update of the two: I've renamed what I was calling &amp;quot;provisioners&amp;quot; to &amp;quot;providers&amp;quot;. This is a bit of an attempt to align my terminology with that of other tools like &lt;a href=&quot;https://developer.hashicorp.com/terraform/language/providers&quot;&gt;Terraform&lt;/a&gt;. Ultimately when deploying real instances I'll need something to install/configure the hob-server component on the new machine, and it might make sense for &lt;em&gt;that&lt;/em&gt; to be called a &amp;quot;provisioner&amp;quot;. So I'm calling the part that interacts with cloud providers a &amp;quot;provider&amp;quot;. So much of this terminology is overloaded in devops tooling, but so it goes. :)&lt;/p&gt;&lt;p&gt;But the bigger change: the program now supports persistence! In practice, this means that you can shut down and restart the program (primarily the &lt;code&gt;boss&lt;/code&gt;), and when it comes back online it will remember the other instances that it's created.&lt;/p&gt;&lt;p&gt;This took a bit of troubleshooting (the errors you get when you forget something currently aren't as clear as they could be) but ultimately I was pleasantly surprised at how few changes I had to do to add persistence support!&lt;/p&gt;&lt;p&gt;The &lt;a href=&quot;https://files.spritely.institute/docs/guile-goblins/latest/Persistence.html&quot;&gt;Goblins docs on persistence&lt;/a&gt; explain this in more detail than I can here, but the changes mostly boiled down to:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Defining persistence environments for each custom object (and their dependencies)&lt;/li&gt;&lt;li&gt;Using &lt;code&gt;define-actor&lt;/code&gt; instead of &lt;code&gt;define&lt;/code&gt; for each of my objects&lt;/li&gt;&lt;li&gt;Pulling some of the variable definitions within each object into the object's constructor as optional parameters&lt;/li&gt;&lt;li&gt;Spawning my objects in persistent vats&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Walking through these:&lt;/p&gt;&lt;h2&gt;Defining persistence environments&lt;/h2&gt;&lt;p&gt;Each module that defines new objects needs to define a &amp;quot;persistence environment&amp;quot;. For &lt;code&gt;hob.scm&lt;/code&gt;, that looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define hob-env
  (make-persistence-env
   `((((gobs-of-machines hob) ^hob-server-presence) ,^hob-server-presence)
     (((gobs-of-machines hob) ^hob-client-presence) ,^hob-client-presence))
   #:extends common-env))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This gives Goblins some information it needs to snapshot and rehydrate objects: the module that the object is found in, the name of that object's constructor within that module, and the &amp;quot;object rehydrator&amp;quot; - which seems to be a direct reference to the object's constructor.&lt;/p&gt;&lt;p&gt;We extend another persistence env, &lt;code&gt;common-env&lt;/code&gt;, because the hob-client uses a &lt;code&gt;ghash&lt;/code&gt; to store bindings. So we need to tell Goblins how to persist &lt;code&gt;ghash&lt;/code&gt;es too, and &lt;code&gt;(goblins actor-lib common)&lt;/code&gt; provides a persistence env for the objects defined there that we can inherit from.&lt;/p&gt;&lt;h2&gt;Using &lt;code&gt;define-actor&lt;/code&gt; and pulling more into object constructors&lt;/h2&gt;&lt;p&gt;Goblins provides a macro called &lt;code&gt;define-actor&lt;/code&gt; that handles a lot of the persistence machinery for us. Using it in practice for e.g. the &lt;code&gt;hob-client-presence&lt;/code&gt; meant changing from this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define (^hob-client-presence bcom)
  (define bindings (spawn ^ghash))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;...to this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define-actor (^hob-client-presence bcom #:optional (bindings (spawn ^ghash)))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Instead of using an inner definition, I'm defining the &lt;code&gt;bindings&lt;/code&gt; hash table as an optional parameter to the object constructor, with its default value set to a newly spawned &lt;code&gt;ghash&lt;/code&gt;. To quote the Goblins manual:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;In most cases, and usually when using ‘define-actor’, we need to think the behavior and state being determined by the constructor, not relying on internal state.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;When the program starts, Goblins will recreate each object by spawning a new object with the same parameters, so moving state like this into the constructor allows it to recreate the previous state of the object.&lt;/p&gt;&lt;h2&gt;Using persistent vats&lt;/h2&gt;&lt;p&gt;This was the hardest part to work out.&lt;/p&gt;&lt;p&gt;To make use of Goblins's persistence features, you need to spawn your objects inside special vats that are persisted. The storage mechanism is pluggable, but for the time being the only one that actually saves to disk is the &lt;code&gt;syrup-store&lt;/code&gt;, so for now I'm using that. Spawning a &lt;code&gt;syrup-store&lt;/code&gt; looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define dummy-vat-store (make-syrup-store &amp;quot;/tmp/gobs-dummy-state&amp;quot;))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If I only had one vat to deal with, this (along with the persistence environment stuff mentioned in an earlier section) would be all that I would need to spawn a persistent vat. However, I had previously designed the application such that the &lt;code&gt;dummy-machine&lt;/code&gt; and &lt;code&gt;hob-client&lt;/code&gt; objects lived in a separate vat, to roughly simulate the fact that in reality these would be running on the newly provisioned machine.&lt;/p&gt;&lt;p&gt;Goblins persists one vat at a time, so what do you do when you have objects in two different vats holding references to each other? Well, there is a mechanism for that too - you can make use of something called a &lt;code&gt;persistence-registry&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define persistence-vat (spawn-vat))
(define persistence-registry
  (with-vat persistence-vat
            (spawn ^persistence-registry)))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And then each time you spawn a new persistent vat, you pass a reference to the persistence registry into the &lt;code&gt;spawn-persistent-vat&lt;/code&gt; call:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define-values (dummy-vat dummy-provider)
  (spawn-persistent-vat
   dummy-env
   (lambda ()
     (spawn ^dummy-provider))
   dummy-vat-store
   #:persistence-registry persistence-registry))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;One noteworthy thing about &lt;code&gt;spawn-persistent-vat&lt;/code&gt; is that when using it, you spawn the first object in the vat at the same time as the vat itself. This first object acts as the &amp;quot;root&amp;quot; of the persistence graph, and for other objects in this vat to be persisted, this first object needs to hold a reference to them. (This will be important later.)&lt;/p&gt;&lt;p&gt;Also, If you're paying close attention, you may notice that this isn't where the &lt;code&gt;dummy-provider&lt;/code&gt; was previously spawned, and there's a reason for that.&lt;/p&gt;&lt;p&gt;Previously, I was creating a new vat for each new machine, and this became a problem, because vats aren't in the list of data types that can appear in a persistence graph! (Even persistent vats, it seems - though I wonder if that could be supported at some point or if there are hurdles to implementing that.)&lt;/p&gt;&lt;p&gt;So I had to refactor a bit. Now, the &lt;code&gt;boss&lt;/code&gt; takes an extra &lt;code&gt;providers&lt;/code&gt; parameter, which is a &lt;code&gt;ghash&lt;/code&gt; whose keys are each the provider name and the values are references to a provider object:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define-actor (^boss bcom #:key [providers (spawn ^ghash)] [machines (spawn ^ghash)])&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Essentially I'm sidestepping the above limitation by spawning the &lt;code&gt;dummy-provider&lt;/code&gt; in a new persistent vat first, and then passing it into the &lt;code&gt;boss&lt;/code&gt; as an argument (with the &lt;code&gt;dummy-provider&lt;/code&gt; modified to spawn each new &lt;code&gt;dummy-machine&lt;/code&gt; in the same vat rather than spawning a new one each time).&lt;/p&gt;&lt;p&gt;And then, having done that, we can spawn the persistent vat our &lt;code&gt;boss&lt;/code&gt; will live in:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define syrup-store (make-syrup-store &amp;quot;/tmp/gobs-state&amp;quot;))
(define-values (my-vat my-boss)
  (spawn-persistent-vat
   boss-env
   (lambda ()
     (let* ((ht (spawn ^ghash)))
       ($ ht 'set 'dummy dummy-provider)
       (spawn ^boss #:providers ht)))
   syrup-store
   #:persistence-registry persistence-registry))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, the thing that had me scratching my head for a while had to do with a little quirk of that vat independence I mentioned earlier, as well as with the requirement that the root retain a reference to objects in that vat that will be persisted. Previously, when creating a new machine, the &lt;code&gt;hob-server&lt;/code&gt; for the new machine would ultimately get a reference to the new &lt;code&gt;hob-client&lt;/code&gt;. But the provider wasn't keeping a reference to that newly created &lt;code&gt;hob-client&lt;/code&gt; anywhere, and so when rehydrating the object graph it didn't come back.&lt;/p&gt;&lt;p&gt;Fixing this just involved &lt;a href=&quot;https://git.sr.ht/~jfred/gobs-of-machines/commit/a21407d7f41ea1e774e0572076eb52344945e2b2&quot;&gt;making the &lt;code&gt;dummy-machine&lt;/code&gt; object persist its &lt;code&gt;hob-client&lt;/code&gt; and making the &lt;code&gt;dummy-provider&lt;/code&gt; persist each of the &lt;code&gt;dummy-machine&lt;/code&gt;s&lt;/a&gt;, but it took a little bit of puzzling to figure out.&lt;/p&gt;&lt;h2&gt;Persistence in action&lt;/h2&gt;&lt;p&gt;Phew! Having made those changes, persistence now works:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;scheme@(gobs-of-machines main)&amp;gt; (define-values (vat boss) (start-daemon))
scheme@(gobs-of-machines main)&amp;gt; ,enter-vat vat
Entering vat '2'.  Type ',q' to exit.  Type ',help goblins' for help.
goblins/2@(gobs-of-machines main) [1]&amp;gt; ($ boss 'create-machine &amp;quot;test&amp;quot;)
dummy-provider: In a real implementation, this would talk to a cloud provider
goblins/2@(gobs-of-machines main) [1]&amp;gt; dummy-machine: Creating new machine
dummy: Registered new client machine

goblins/2@(gobs-of-machines main) [1]&amp;gt; ($ boss 'list-machines)
$6 = (&amp;quot;test&amp;quot;)

&amp;lt;...then after killing and restarting the repl...&amp;gt;

scheme@(gobs-of-machines main)&amp;gt; (define-values (vat boss) (start-daemon))
scheme@(gobs-of-machines main)&amp;gt; ,enter-vat vat
Entering vat '2'.  Type ',q' to exit.  Type ',help goblins' for help.
goblins/2@(gobs-of-machines main) [1]&amp;gt; ($ boss 'list-machines)
$6 = (&amp;quot;test&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Success!&lt;/p&gt;&lt;p&gt;Obviously, there are still a couple tweaks that need to be made before this is really useful as a standalone application. There are some hardcoded &lt;code&gt;/tmp&lt;/code&gt; filenames lying around for the two persistent vats; the location for those needs to be configurable. It still needs a command-line entrypoint and a config file, so you can start and configure it from outside a REPL. And it still needs at least one real provider implementation! But it's a start. :)&lt;/p&gt;</content></entry><entry><title>Prototyping a machine deployment tool with Spritely Goblins</title><id>https://www.terracrypt.net/posts/gobs-of-machines.html</id><author><name>Jonathan Frederickson</name><email>jonathan@terracrypt.net</email></author><updated>2025-01-07T12:10:00Z</updated><link href="https://www.terracrypt.net/posts/gobs-of-machines.html" rel="alternate" /><content type="html">&lt;p&gt;Wrapping up December Adventure for this year and related to &lt;a href=&quot;/posts/guix-goblins-fleet.html&quot;&gt;my last post&lt;/a&gt;, here's some early prototyping I did over the holidays of a machine management tool. After I posted the last post, I had a conversation with some of my friends in which it was difficult to convey exactly how this might work, so I'm writing this up partly to serve as an explainer for my thought process.&lt;/p&gt;&lt;p&gt;In this post I may assume some basic familiarity with &lt;a href=&quot;/garden/ocap.html&quot;&gt;object capabilities&lt;/a&gt; and &lt;a href=&quot;https://spritely.institute/goblins/&quot;&gt;Spritely Goblins&lt;/a&gt;, though I'll try to explain things to some degree as I go.&lt;/p&gt;&lt;h2&gt;Goals&lt;/h2&gt;&lt;p&gt;From a high level, what I'd like to accomplish is something like: you have a centralized infra management tool that's responsible for provisioning new machines. When you want to create a new machine, you send a message to that management tool, and the response you get back is a reference to some management interface for that new machine.&lt;/p&gt;&lt;p&gt;Crucially, this system must effectively avoid the &lt;em&gt;trust bootstrapping problem&lt;/em&gt;; that is to say, the new instance must be able to securely connect to the management tool, and the management tool must have confidence that the new instance is what just connected to it. Despite seeming simple, this has been surprisingly difficult to accomplish with common devops tools in my experience! It can be done, but often either is not or takes a lot of work. So that's something I'd like to address right out of the gate.&lt;/p&gt;&lt;p&gt;Furthermore, I'd like to make it straightforward to connect services running on different machines to each other. Even when you have a single deployment tool deploying two different services, it's often more involved than you would hope to get those two services talking to each other. Consider the example of a web application and a database instance deployed specifically for that web application. You've deployed the web application onto one machine, and the database instance on another, and you need the web application to connect to the database. What do you need for this? Typically, at least:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The ability to generate login credentials to the database for the web application to use&lt;/li&gt;&lt;li&gt;The ability to modify the web application's configuration to use said database instance&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In my experience, both of those steps are often done semi-manually; often someone will manually generate database credentials to use, and while the configuration of the webapp will be config managed, it'll pull those static database credentials from some source (maybe it's a &lt;a href=&quot;https://getsops.io/&quot;&gt;sops&lt;/a&gt;-encrypted file, maybe it's in a secrets manager somewhere, etc). When it is done automatically via something like &lt;a href=&quot;https://developer.hashicorp.com/vault/api-docs/secret/databases/mysql-maria&quot;&gt;Vault&lt;/a&gt;, this relies on that separate tool with its own policies, and bootstrapping client trust to Vault is itself a whole rabbit hole!&lt;/p&gt;&lt;p&gt;Wouldn't it be nice if your provisioning tool could take care of this kind of thing for you?&lt;/p&gt;&lt;h2&gt;Building a prototype&lt;/h2&gt;&lt;p&gt;I've built a basic prototype of some of what I have in mind called &lt;a href=&quot;https://git.sr.ht/~jfred/gobs-of-machines&quot;&gt;gobs-of-machines&lt;/a&gt;. I'll probably work on it (and document it) more in the future, but for now I'd like to go over what I have so far.&lt;/p&gt;&lt;p&gt;The system I've built has a few parts, most with D&amp;amp;D-esque names. There's the &lt;strong&gt;boss&lt;/strong&gt;, which is responsible for triggering the provisioning process of new machines and keeping track of the machines it's provisioned. There are &lt;strong&gt;provisioners&lt;/strong&gt;, which are what would call out to the APIs of a given cloud provider and provision a new machine with some specified user data. And then there's the &lt;strong&gt;hob&lt;/strong&gt;, a service in two parts - one colocated with the boss, and another running on each deployed machine. This acts as the communication channel between the boss and each machine. (Named after the &lt;a href=&quot;https://en.wikipedia.org/wiki/Hob_(folklore)&quot;&gt;household spirit or hobgoblin&lt;/a&gt;, not the &lt;a href=&quot;https://en.wiktionary.org/wiki/hob#Noun&quot;&gt;stove&lt;/a&gt;. Maybe I'll rename it if it gets too confusing, but hobgoblin is pretty verbose. Names, ya know!)&lt;/p&gt;&lt;h3&gt;Boss&lt;/h3&gt;&lt;p&gt;Starting with the boss, we'll create a Goblins object with a hashtable inside it. This will map a human-readable name for each machine to an object we can use to communicate with that machine.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(define (^boss bcom)
  (define machines (spawn ^ghash))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For the time being, since I haven't implemented any cloud provider provisioners, we'll use a dummy provisioner as a placeholder. In a real implementation we'd want a more sophisticated way to manage provisioners for multiple providers, but for now let's just create an instance of the dummy provisioner inside the boss object.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;  (define dummy-provisioner (spawn ^dummy-provisioner))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We'll add a getter methods to get a specific machine from the hashtable by name, and a list method to list all the machines that have been registered:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;  (methods
   [(get-machine name)
    ($ machines 'ref name)]
   [(list-machines)
    (ghash-fold ghash-keys '() ($ machines 'data))]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For those coming from other object oriented programming languages, this will hopefully feel somewhat familiar. We're defining the constructor for an object (in Goblins's convention, the &lt;code&gt;^&lt;/code&gt; at the beginning of names like &lt;code&gt;^boss&lt;/code&gt; denotes a constructor) and defining some methods for that object. There are a few Goblins-specific quirks to explain here:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;$&lt;/code&gt; in the &lt;code&gt;get-machine&lt;/code&gt; method stands for a synchronous method call on another Goblins object (with some transactional functionality that I won't get into yet)&lt;/li&gt;&lt;li&gt;The implementation of the &lt;code&gt;list-machines&lt;/code&gt; method is a bit funky, because Goblins's &lt;code&gt;ghash&lt;/code&gt; objects don't have a built-in method to list all the keys in the hashtable. So what I'm doing here is grabbing the underlying hashtable and pulling out the keys from it. (&lt;code&gt;ghash-keys&lt;/code&gt; is a procedure whose implementation I've elided for brevity, check &lt;a href=&quot;https://git.sr.ht/~jfred/gobs-of-machines/tree/master/item/gobs-of-machines/boss.scm&quot;&gt;the source&lt;/a&gt; if you're curious.)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;One thing worth noting about Goblins programming is that, unlike some other object oriented programming languages like Python, you should generally think of method calls as messages sent between objects. It's a very &lt;a href=&quot;https://softwareengineering.stackexchange.com/a/58732&quot;&gt;Alan Kay-style object system&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Okay, now for the only particularly interesting part of the boss, the &lt;code&gt;create-machine&lt;/code&gt; method:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;   [(create-machine name)
    (define hob-server (spawn ^hob-server-presence))
    (on (&amp;lt;- dummy-provisioner 'new-machine hob-server) ;; TODO selectable provisioners
        (lambda (ret)
          ($ machines 'set name hob-server)))]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This one adds a couple new things to go over. Within the body of the &lt;code&gt;create-machine&lt;/code&gt; method, we're spawning one of the components of the &lt;code&gt;hob&lt;/code&gt; service - the one that lives alongside the &lt;code&gt;boss&lt;/code&gt;. We're then sending an asynchronous message to the provisioner (that's what &lt;code&gt;&amp;lt;-&lt;/code&gt; does) and passing it a reference to the &lt;code&gt;hob&lt;/code&gt; object that we created.&lt;/p&gt;&lt;p&gt;Async messages, as in some other languages like JavaScript, return promises that will be fulfilled later rather than waiting for the response to come back. In Goblins, you can trigger an action when a promise is resolved with &lt;code&gt;on&lt;/code&gt;. In this case, when the promise is resolved (i.e. when the boss gets a response from the provisioner), we add an entry to the hashtable created above for the new server. Currently I have it waiting until after hearing back from the provisioner to avoid adding entries for new nodes if provisioning fails, but we could just as well create a &amp;quot;pending&amp;quot; entry in the hashtable and update it when provisioning succeeds.&lt;/p&gt;&lt;h3&gt;Provisioners&lt;/h3&gt;&lt;p&gt;Now that we've seen the code that kicks off the provisioning process, let's take a look at what the provisioner itself does. For now I only have a dummy provisioner with one method to try out the idea:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(define (^dummy-provisioner bcom)
  (methods
   [(new-machine hob-server-presence)
    (display &amp;quot;dummy-provisioner: In a real provisioner, this would talk to a cloud provider\n&amp;quot;)
    (let ((new-vat (spawn-vat)))
      (with-vat new-vat
                (define machine (spawn ^dummy-machine))
                ($ machine 'provision hob-server-presence)))]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is the method of the provisioner that we saw the boss call earlier.&lt;/p&gt;&lt;p&gt;Part of this again deserves some explanation, because it's Goblins-specific. Because we're not actually provisioning a new VM at this stage, I'm instead spawning a new &amp;quot;vat&amp;quot; to run some extra code in. A vat is Goblins's mechanism of concurrency; it's an event loop containing objects. Objects within the same vat can make synchronous method calls between each other, while objects in different vats can only send asynchronous method calls. Objects on separate machines can communicate with each other via CapTP, but they will necessarily be in different vats and so can only communicate asynchronously.&lt;/p&gt;&lt;p&gt;Running part of this code in a separate vat is my attempt to simulate running on a separate machine, though of course there are a few things that would be different in a real provisioner:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The provisioner must be able to deploy some code to the new machine. There's a client component that needs to run on the new machine for this all to work.&lt;/li&gt;&lt;li&gt;Crucially, the provisioner must be able to pass the hob-server reference to the new machine.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The latter is trivial in the dummy provisioner case, when everything is running on the same machine, but Goblins has a trick up its sleeve that makes it possible across machines. If you have OCapN set up, you can &lt;a href=&quot;https://files.spritely.institute/docs/guile-goblins/latest/Using-the-CapTP-API.html&quot;&gt;serialize the reference to the hob-server reference as a sturdyref&lt;/a&gt; so you can send it over the network as a string. In a cloud provider that supports user data (&lt;a href=&quot;https://techdocs.akamai.com/cloud-computing/docs/overview-of-the-metadata-service&quot;&gt;Linode, for example&lt;/a&gt;), you can include the sturdyref in user data for the new instance. The code running on the remote machine can then enliven the sturdyref, turning it back into a live reference, after which point objects on each machine can send asynchronous messages to each other as usual.&lt;/p&gt;&lt;p&gt;The dummy provisioning code that runs in the new vat doesn't do a whole lot; it looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define (^dummy-machine bcom)
  (methods
   [(provision hob-server-presence)
    (display &amp;quot;dummy: Provisioning new machine\n&amp;quot;)
    (let ((client (spawn ^hob-client-presence)))
      (on (&amp;lt;- hob-server-presence 'register client)
          (lambda (ret)
            (display &amp;quot;dummy: Registered new client machine\n&amp;quot;))))]))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Essentially, it just spawns a new instance of a &lt;code&gt;hob-client-presence&lt;/code&gt; on the new machine, registers it with the associated hob server, and logs that it's done so. More on what that does in a minute. In a real provisioner, this might also be where we set up persistence for the &lt;code&gt;hob-client-presence&lt;/code&gt; object, because we'll want that to stick around across reboots.&lt;/p&gt;&lt;h3&gt;Hobs&lt;/h3&gt;&lt;p&gt;So I've shown how you start the provisioning process, and I've shown what a trivial provisioner might do. That covers some initial provisioning, but what does the interface to machines after that point look like? That's the job of the &lt;code&gt;hob&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;As I mentioned before, the &lt;code&gt;hob&lt;/code&gt; is a service in two parts: one that lives on the management server (alongside the &lt;code&gt;boss&lt;/code&gt;, one instance per machine), and one that lives on each machine. As with the other components of this system, these are implemented as Goblins objects.&lt;/p&gt;&lt;p&gt;We saw above that the one thing the machine-side component did was to register the hob-client with its associated server. Let's take a look at the server:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define-actor (^hob-server-presence bcom #:optional (client #f))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Each machine gets a hob-server instance, and each hob-server instance will communicate with its associated hob-client instance. The hob-server therefore needs to know where its hob-client is. So we'll pass in the client as an optional parameter, defaulting to false initially.&lt;/p&gt;&lt;p&gt;The next part has a few Goblins-isms that deserve some explanation:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;  (define pending-beh
    (methods
     [(register client-presence)
      (bcom (^hob-server-presence bcom client-presence))]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We're using &lt;code&gt;methods&lt;/code&gt; like before, only now we're assigning it to a variable. What? Well, it turns out &lt;code&gt;methods&lt;/code&gt; isn't a special, core part of the language - it's a macro that emits a function dispatching on a method name as its first argument. And because it emits a function, we can assign that function to a variable as we would anything else. We'll see why this is useful in a bit.&lt;/p&gt;&lt;p&gt;The other oddity here is the last line in the &lt;code&gt;register&lt;/code&gt; method - &lt;code&gt;(bcom (^hob-server-presence bcom client-presence))&lt;/code&gt;. I didn't explain it above, but you may have noticed that each actor has &lt;code&gt;bcom&lt;/code&gt; in its argument list. This is a capability that allows an object to &amp;quot;become&amp;quot; something else; it lets Goblins objects act as a sort of state machine. If the last thing that an object does on a method call is &lt;code&gt;bcom&lt;/code&gt; something else, then the next time you make a call to that object, it'll use the behavior of that new thing instead of its original behavior. Here, the argument to &lt;code&gt;bcom&lt;/code&gt; is the constructor for a new &lt;code&gt;hob-server-presence&lt;/code&gt;, but this time with a client defined.&lt;/p&gt;&lt;p&gt;When we spawn a new &lt;code&gt;hob-server&lt;/code&gt; initially, it doesn't know where its client is! It can't at that point, because the machine it's on hasn't been provisioned yet. Only after the new machine has been provisioned and its &lt;code&gt;hob-client&lt;/code&gt; has been spawned can the server possibly know where it is. So we initially create the &lt;code&gt;hob-server&lt;/code&gt; in a sort of pending state, where it's just sitting there waiting for a client to register to it. Only after a client registers does it transition to its active behavior. And what is its active behavior?&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;  (define active-beh
    (methods
     [(register-binding name svc-cap)
      (&amp;lt;- client 'register-binding name svc-cap)]
     [(list-bindings)
      (&amp;lt;- client 'list-bindings)]
     [(get-binding name)
      (&amp;lt;- client 'get-binding name)]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For now, it only does three things: it lets you register a service binding, list the already registered service bindings, and get a service binding by name. Each of these method calls is passed through directly to the underlying &lt;code&gt;hob-client&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;What is a service binding? Inspired by &lt;a href=&quot;https://blog.cloudflare.com/workers-environment-live-object-bindings/&quot;&gt;this CloudFlare Workers blog post&lt;/a&gt;, a binding is a mapping between a human-readable name (something like &lt;code&gt;db&lt;/code&gt; for example) and a service capability (which is currently any arbitrary capability, but it may be better to have a defined interface for these capabilities later on). This gives each machine in the system its own namespace for looking up services. For example, an application could be configured to look up and connect to the &lt;code&gt;db&lt;/code&gt; service, and exactly which service that ends up connecting to depends on the bindings available on that machine.&lt;/p&gt;&lt;p&gt;Lastly, the &lt;code&gt;hob-server&lt;/code&gt; needs an initial behavior to start with. The client was an optional parameter, so we'll choose the active behavior if that parameter is truthy (which it would be if we've already registered a client) or the pending behavior if it's false:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;  (if client
      active-beh
      pending-beh))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now for the client side. Its implementation is pretty similar to the &lt;code&gt;boss&lt;/code&gt; as it turns out, because it's doing a very similar thing - mapping from a human-readable name to something stored in a hash table:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;(define (^hob-client-presence bcom)
  (define bindings (spawn ^ghash))
  (methods
   [(register-binding name svc-cap)
    ($ bindings 'set name svc-cap)]
   [(list-bindings)
    (ghash-fold ghash-keys '() ($ bindings 'data))]
   [(get-binding name)
    ($ bindings 'ref name)]))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(An aside on naming - you might be wondering why the hob-client and hob-server are called &amp;quot;presences&amp;quot;. The terminology, and the rough outlines of this architecture, come from something known in the ocap world as &lt;a href=&quot;http://habitatchronicles.com/2019/08/the-unum-pattern/&quot;&gt;the unum pattern&lt;/a&gt;.)&lt;/p&gt;&lt;h2&gt;Putting it all together&lt;/h2&gt;&lt;p&gt;Now that we have all this in place, let's think a bit about what this allows us to do. Imagine that we've created two machines, say, &lt;code&gt;app-machine&lt;/code&gt; and &lt;code&gt;db-machine&lt;/code&gt;. On &lt;code&gt;db-machine&lt;/code&gt;, imagine that we're running a database service (and assume for a moment that the database service itself speaks CapTP for simplicity's sake). On the database server, you could run:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;($ hob-client 'register-binding &amp;quot;db&amp;quot; db-cap) ;; running on db-machine&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You could then do this, from the boss:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(define db-machine ($ boss 'get-machine &amp;quot;db-machine&amp;quot;))
(define app-machine ($ boss 'get-machine &amp;quot;app-machine&amp;quot;))
(define db-cap (&amp;lt;- db-machine 'get-binding &amp;quot;db&amp;quot;))
(&amp;lt;- app-machine 'register-binding &amp;quot;db&amp;quot; db-cap)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, &lt;code&gt;app-machine&lt;/code&gt; has access to the DB service via its capability!&lt;/p&gt;&lt;pre&gt;&lt;code&gt;($ hob-client 'get-binding &amp;quot;db&amp;quot;) ;; running on app-machine&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Of course, there aren't any database services that speak CapTP yet that I know of, but you can see the above flow working if you define &lt;code&gt;db-cap&lt;/code&gt; to be something like a &lt;code&gt;ghash&lt;/code&gt; for testing purposes.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;This is still a rough prototype, and there's lots of details I haven't covered yet. For example, you may want to &lt;a href=&quot;https://en.wikipedia.org/wiki/Object-capability_model#Glossary_of_related_terms&quot;&gt;attenuate&lt;/a&gt; the capability to a service exposed by one machine before passing it on to another. And because most existing services do not natively speak CapTP, you'd need to write a capability-style wrapper for them. This may be more or less difficult, depending on the service in question, and supporting attenuation in particular in a wrapper is likely to be a challenge.&lt;/p&gt;&lt;p&gt;I also haven't defined a declarative interface for passing service references between machines. That's possible to build on top of these foundations, but is definitely a lot more involved than what I've shown so far. For long-term administrative tasks, you may want to be able to define a service graph (i.e. &amp;quot;service db on db-machine points to service db on app-machine&amp;quot;) and have the system transfer those capabilities between the machines automatically.&lt;/p&gt;&lt;p&gt;But rough as it is, I hope this has given you some insight into the things that are possible to build in a capability framework. I know in my professional life there have been many times when I've wished connecting services to each other were a lot more straightforward, and so I wanted to take a crack at showing what's possible. Hopefully I've at least somewhat succeeded. :)&lt;/p&gt;</content></entry></feed>