Moving My Sensor Network onto Manifold

Cabin temperatures in Home Assistant

I have been working to make Manifold a good framework for building pico meshes, the kind I use for my network of LoRaWAN sensors. The new Manifold API doesn't have a UI like the old Manifold did. I want to use Home Assistant (HA) for that and recently created a custom HA integration. With the groundwork laid, it was time to move my actual sensor network onto the new framework running on the updated pico engine. This post describes that move and the problems I ran into, and fixed, along the way.

Manifold as a Framework for Pico Meshes

Manifold began as an application for managing your things and creating communities to group them together. The primary application was Safe and Mine, a QR-code-based tagging system to identify your keys, bags, and mugs. Manifold was expandable with custom applications (written in KRL) that could be added to each thing.

When I rebuilt it as the Manifold API, I stopped treating it as a finished app and started treating it as a framework, a set of domain rulesets other people can extend to build their own meshes. A pico mesh is a small network of independent, addressable computational things, each with its own state, its own rules, and its own relationships. It still supports Safe and Mine, but I wanted it to be more than that—a personal space to manage both inactive (like your mug) and active (like a temperature sensor) things. The reason to build on Manifold is ownership; the mesh belongs to the person who runs it, not to me and not to a platform, and they decide what connects to it and what it exposes.

That distinction is the whole point. I've been working for years to build alternatives to what I call the CompuServe of Things. A sensor network you rent from a vendor is legible to the vendor first and to you second. A sensor network that runs as your own pico mesh answers to you, and the framework underneath it exists to keep that relationship intact as the network grows.

The Network I Was Moving

The network I wanted to move is not a demo. It is a working LoRaWAN deployment I have written about before, starting with easier IoT deployments on Helium and then the temperature sensors in a remote pumphouse. I have temperature probes in the crawl space of my cabin, on the north side deck, and in my beehive in addition to the pumphouse. Those sensors report over Helium, and until now they ran on the old sensor-network code, essentially recreating the features of the Manifold framework in addition to their specific duties interpreting and managing the payloads received over LoRaWAN.

Rebuilding the network on top of Manifold simplifies the code and gives the sensors additional capabilities. Each sensor becomes a thing in a community, with an owner pico above the Manifold pico that ties the whole mesh together. The structure is easier to see than to describe, so here is the mesh as it stands after the move.

The sensor network as a pico mesh
The sensor network as a pico mesh, with the owner and Manifold picos above the individual sensor things (click to enlarge)

Everything below the Manifold pico is a sensor or a community. The pumphouse, cabin crawl space, cabin north side deck, triple-temperature probe, and beehive are sensors. The Sensors pico is a Manifold community pico for the sensors. It handles things like notifications, sensor initiation, and reading aggregation. Moving to Manifold didn't change what the sensors measure, but it makes them more capable and manageable. And having them in a standard mesh means I can write HA integrations that work for lots of different meshes.

Home Assistant as the Interface

Because the new Manifold API has no interface of its own, I spent some time making Home Assistant fill that role. In Using Home Assistant with Manifold I described the integration: Home Assistant runs the pico engine's OAuth flow, comes away with a scoped token, and reads the mesh through it. That gives me dashboards, history, and alerts on software many people already run at home, without my having to write a UI of my own. The sensor network ships a companion Home Assistant component so its sensor things show up as real temperature and humidity entities, not just generic mesh objects. The code serves as an example of how to write HA companion components that work with the Manifold integration.

Where It Broke: OAuth Meets Webhooks

The initial port looked good. Every sensor came across, the communities lined up, and the readings flowed into the mesh the way they had before. The trouble started when I wired the mesh to Home Assistant, because that connection depends on the OAuth protection I added to the engine in Identity for the Pico Engine. Turning on OAuth secured the mesh against outside access, which is exactly what I wanted for Home Assistant; it also secured the mesh against webhook calls from Helium, which is not what I wanted at all.

Helium delivers sensor readings by calling a webhook defined on the pico for a specific sensor. The Helium console is software sitting outside my mesh that needs to POST data in, on its own schedule, with no human present to complete a login. The same protection that made Home Assistant's access deliberate and revocable made the inbound webhook fail with an authorization error. That is the tension at the center of this move: authentication that assumes a person in the loop breaks the moment a machine needs to knock on the door.

Two Ways Through

There are two reasonable ways to let a machine through without tearing down the protection around everything else. Picos define webhooks by creating channels. Each channel has a policy saying what events and queries are allowed on that channel.

  • Client-credentials channels. The engine already supports OAuth client credentials for a channel. I described this feature in Identity for the Pico Engine. A channel configured this way lets the caller authenticate as itself, against that one channel, rather than as a person against the whole mesh. You configure the bearer token in Helium as part of defining the webhook and Helium includes it on each POST.
  • Owner-declared exempt channels. Alternately, the mesh owner can mark a channel as exempt from the OAuth protection. This is only safe when the channel's policy is tight enough to keep the exemption from becoming an open door, and in this case it is, because the channel accepts one narrow shape of sensor data and nothing else.

Both of these approaches rely on the owner being careful about scoping the authority of the webhook so that it doesn't represent a security threat. Neither one weakens the mesh as a whole, and neither one hands a machine the standing of a person. I updated the pico engine to support the owner-declared exemption, so the choice now belongs where it should, with the person who runs the mesh, decided channel by channel rather than for the network all at once.

The Window onto the Mesh

With data flowing again, Home Assistant does exactly what I hoped. The dashboard at the top of this post is my cabin: the pumphouse, the crawl space, the north side deck, each updating every few minutes from the sensor network now running on Manifold. I get history, thresholds, and a picture of the current temperatures at a glance, all from software I run.

Home Assistant also makes alerting easier. I already had notifications on the old setup, but each one was its own bit of wiring off to the side; Home Assistant keeps the readings, the history, and the rules that act on them together in one place. I can build an automation directly on a reading, so a low temperature in the pumphouse sends me a notification while there is still time to act, rather than after a freeze has cracked a pipe and left the cabin without water. Having that alongside everything else I watch, instead of bolted on separately, is exactly what I want an interface for the mesh to do.

None of this is a new capability so much as a boundary drawn in the right place. The reading Helium sends and the reading Home Assistant shows are the same as they were a year ago. What changed is the software and systems are less creaky and easier to manage and update. The mesh belongs to the person who runs it, and Home Assistant is just a window onto it.


Software-Defined Three-Way Switch

Lights over the fireplace benches

As part of our remodel, Lynne wanted lights over the built-in benches on either side of our fireplace. The fireplace itself made it hard to run both fixtures back to a single switch, so the easy path left us with one switch at each end of the hearth. That works, but it means anyone who wants the benches lit has to cross the room and flip two switches. It's a small annoyance, the first-world that the physical world imposes from time to time. Fortunately, software can fix it.

Both switches are Inovelli Blue Series 2-1 dimmers, Zigbee devices that report their state and take commands over the network as readily as a person flips them by hand. That makes them programmable in a way an ordinary switch is not; the paddle still does the obvious thing, but the switch is also something software can watch and control. I've leaned on that elsewhere in the house. One of them runs the bathroom fan, turning it on by itself when the humidity spikes and off again once the room dries out, so nobody has to remember.

The fix for the benches uses the same idea. Each light keeps its own switch, and a pair of Home Assistant automations wires the two together in software: when one switch turns on, it turns on the other, and the same for off. Flip either paddle and both fixtures respond, which is exactly how a three-way switch behaves when it controls a single light. Here there are two lights and two circuits that never meet in the wall, made to act as one from the automation layer instead.

And nothing about this arrangement is fixed, either. The same two switches could join a scene that dims the whole room for a movie, answer a voice command, or turn themselves off when the house goes to bed, none of which requires a visit from an electrician. Because the coordination lives in software rather than in the wiring, teaching the switches a new behavior simply requires writing another automation, not running another wire. The pairing I set up today is just the first thing I have asked them to do.

The wires in the wall didn't change; the behavior did. That's the beauty of adding a little software to a physical control: the constraints of the wiring are no longer the constraints of the room. When the layout fights you, you don't always have to open the wall. Sometimes you can just change what the switches do.


Photo Credit: Lights over the fireplace benches from Phil Windley (CC BY 4.0)


There's a Personal App for That

The QX3 microscope beside my laptop running Windley Microscope

Over twenty-five years ago, I bought an Intel Play QX3 microscope for my kids to play with. It came with a CD-ROM holding the control software, which, as I recall, ran only on Windows. The microscope then spent the better part of two decades in the back of a cabinet in my office, gathering dust.

I pulled it out recently for my grandkids, hoping the Mac might simply recognize it as a camera. It didn't. I couldn't find any software that would run on a modern machine, and I was about ready to send the whole thing to the thrift store. Then I had an idea: what if I used Claude to write an app for it?

A morning later I had one, and my grandkids were watching the ridges of a seashell fill the screen. The interesting part of this story isn't the microscope; it's that building a custom app for a single obsolete device is now a morning's work instead of a project. That change is going to reshape what we expect software to be.

A Microscope With No Software

The QX3 is a small USB microscope that Intel and Mattel sold around the turn of the century. It magnifies at 10x, 60x, and 200x (using physcial lenses, not software); it has a camera in the head, a light on top and another in the stage, and a focus wheel. For a toy, it is genuinely good, and it still works exactly as well as it did in 2000. The problem is not the hardware; it is everything the hardware expects to talk to.

The QX3 predates USB Video Class, the standard that lets a modern operating system treat any conforming camera as a webcam with no driver at all. To macOS, the QX3 is not a camera; it is an unknown vendor-specific USB device, and the system has no idea what to do with it. Over the years, hobbyists filled that gap with their own drivers and apps for Linux and the Mac. Those projects are mostly dead now.

They died for an ordinary reason. Each one depended on the operating-system internals of its moment, and macOS kept moving: it went 64-bit, it tightened what kernel extensions could do, and it reworked its USB and camera frameworks more than once. Keeping a driver alive for a discontinued children's toy is a lot of unpaid work for an audience of a few, so the maintainers moved on and the code stopped building. The hardware still worked; the software around it rotted away.

Building It With Claude

I opened Claude in Cursor and worked in stages. I didn't begin with a plan for an app; I began by trying to talk to the device at all. Each stage did one small thing and proved it worked before I asked for the next.

  1. Identify the device. I gave Claude the handful of facts the macOS "About This Mac" USB panel showed for the microscope: a vendor ID, a product ID, and not much else.
  2. Blink the lights. I had Claude write a small command-line program that turned the microscope's LEDs on and off. That was the entire test: could code I control make something physical happen across the USB cable? It could.
  3. See through it. Next came a command-line tool that pulled the image the microscope was seeing and saved a snapshot to a file.
  4. Give it a face. Then a real Mac app with a window: switches for the two lights, a brightness slider, a live preview, and a button to take a picture.
  5. Record. After that, movie capture and time-lapse, so my grandkids could watch an ant walk or a drop of water evaporate.
  6. Clean it up. Finally the work that separates a demo from a tool: an app icon, a proper Quit item in the menu, and the usual round of small bug fixes.
The Windley Microscope app showing a live view of a seashell
The Windley Microscope app showing a live view of a seashell (click to enlarge)

The result is a few hundred lines of Swift that talk to the microscope directly over USB. I called it Windley Microscope, which is the kind of name you give something built for exactly one household. It does what the original Windows software did, and only what my grandkids and I actually want it to do.

Why This Works

The QX3 is easy to bring back precisely because it is old. A modern webcam sits behind several layers: USB Video Class, the camera framework, the operating system's device and privacy management. Those layers are what make a new camera "just work," and they are also what you cannot reach around when it doesn't. The QX3 has none of them.

A seashell captured through the QX3
A seashell captured through the QX3 (click to enlarge)

It sits right on the USB wire, speaking a simple protocol, with nothing between my code and the device. The same plainness that made it invisible to macOS made it straightforward to control myself; there was no abstraction to defeat, only a device to address. Simple architecture wins. When the platform declines to capture a device, you are not locked out of it; you are left free to talk to it on your own terms.

An App for an Audience of One

Here is the part that reaches past one microscope. A few years ago I would not have spent two weeks building a custom app to run a discontinued toy for my grandkids; the effort was far larger than the result was worth. I was happy to spend a morning. That shift changes the cost dynamics of software in a profound way.

An app no longer has to be a product. It does not need a market, a store listing, or a user base large enough to justify the build. It can be personal1: written for exactly what one person needs, and for no one else. There is a massive backlog of small software applications that never get written because the audience is one (or small) and the price was two weeks (or two years). That backlog has quietly become approachable. Imagine all the things that will be built because of this profound change in cost.

An important point: this is easy on a laptop because computers still let their owners run whatever code they write and talk to whatever hardware they plug in. It is not easy on iOS, where the platform, not the owner, decides what is allowed to run. The model that let me revive the QX3 in a morning barely exists on the devices most people actually use; that is a decision about how those platforms are built, not a fact of nature. As personal software becomes ordinary, it will press on that decision.

The microscope works again, and that is a small, good thing. The larger thing I got back is the ability to make the computer do the specific thing I want, without waiting for a company to decide enough other people want it too. That capability used to belong to firms with a market to serve. It is starting to belong to the rest of us.


Notes

  1. Personal is not personalized. In 2026, a personalized system is one a company tunes to you from the data it collects about you; the tuning serves the company, and the surveillance that feeds it is the point. A personal app is the reverse: you build or commission it, it runs on your own machine, and it answers only to you. I mean personal in its older, plainer sense: software that belongs to you, not software aimed at you.

Photo Credit: The QX3 microscope beside my laptop running Windley Microscope from Phil Windley (CC BY 4.0)


Authentication Is Largely Solved. Authorization Isn't.

Authorization in Action book cover

My new book, Authorization in Action, is now available from Manning. It's a book about the question that comes after we know who you are: what are you allowed to do? Knowing who someone is doesn't tell you what they should be able to touch, change, or spend. For most of the last two decades I've worked on the first question, proving who someone is; this book is about why the second one is now the one that matters, and how to build systems that answer it well.

The short version of the argument is one I didn't expect to be making a few years ago. Authentication, the act of proving who someone is, has become about as good as we can reasonably ask; passkeys and FIDO have quietly closed most of the gap that kept me up at night in 2005. Authorization, the act of deciding what someone can actually do, is still mostly improvised, buried in application code, and reinvented badly on every team. That imbalance is the reason the book exists.

How I Got Here

When I was CIO for the State of Utah in 2001, I noticed that nearly every problem that reached my desk had an identity component hiding inside it. Consolidating directories so every employee could have a utah.gov address, moving the state's website to a new domain, sorting out who could touch which system: none of these looked like identity problems on the surface, yet all of them turned on knowing who someone was and what they were permitted to do. I didn't have language for it then, but that observation set the direction for everything I've worked on since.

A few years later Doc Searls, Kaliya Young, and I started the Internet Identity Workshop (IIW), and it has now met 42 times. IIW has become the place where the identity community works on its hardest problems together. Along the way I wrote three books; Digital Identity helped enterprises build identity strategies, The Live Web moved the focus from organizations to individuals with their own data and APIs, and Learning Digital Identity finally named the thing I'd been circling for years: identity is fundamentally about relationships, not identifiers. Each book was really an attempt to answer a question the previous one had raised.

While I was finishing Learning Digital Identity, the next question came into focus, and conversations at IIW confirmed it. Knowing who someone is tells you almost nothing about what they should be able to do; the interesting, unsolved work all lives on the far side of authentication. That's the work my new book takes on.

The Second Question

The reason the second question is harder is that it's not one question but several, and they're the ones that actually govern what happens inside a system. What can this person do; under what conditions; on whose behalf; and in which context? Miss any one of them and the rest stop meaning much; the same request can be right for a manager at noon from the office and wrong for a contractor at midnight from an unknown device. A login gets you through the door, but it says nothing about which rooms you can enter, what you can carry out, or whether the person who sent you had the standing to send you at all.

In late 2022 I joined AWS Identity, and one of the teams we worked closely with was building Amazon Verified Permissions and the Cedar policy language. Working at that scale showed me something the theory hadn't: fine-grained authorization doesn't only make a system safer, it makes it more usable. When the rules about who can do what are explicit and external to the code, you can hand people exactly the access they need without either drowning them in prompts or handing over the keys to everything. Getting authorization right is how a system stays both safe and pleasant to use, and those goals stop fighting each other.

Then Came the Agents

What finally convinced me the world needed this book was AI. As agents begin acting on people's behalf, "what is this thing allowed to do, and on whose authority?" stops being a background concern and becomes the whole game. An agent that can read your calendar, spend your money, or send mail as you is only as trustworthy as the boundaries around it, and those boundaries are authorization. I've argued before that authorization is the hard problem in agentic AI, and nothing since has changed my mind.

This is where the technical question turns into a human one. If we can't say precisely what an agent may do on our behalf, we're left choosing between agents that can't do anything useful and agents we have to trust blindly; neither of those is a world I want to live in. Authorization is the infrastructure that lets us delegate real authority to software while keeping it bounded, accountable, and revocable. That's not a convenience feature. It's what makes it possible to act through machines without surrendering to them.

What's in the Book

Authorization in Action follows a fictional company, ACME, as it works its way from the tangled access-control code most teams start with toward policy-based authorization it can actually reason about. The book uses that story to get concrete about the models and mechanics—relationships, roles, attributes, policy languages, and the architecture that separates deciding from enforcing—rather than leaving them as abstractions. This is the book I needed on my own shelf while I was solving these problems as an enterprise architect at BYU, so it's aimed at the developers and architects who have to make these decisions everyday

Identity tells us who is involved. Authorization determines what happens next. I've come to believe that second question is quietly becoming the heart of security, governance, and trust online, and I hope the book makes the case as clearly to you as the last few years have made it to me. You can find Authorization in Action at Manning and coming soon to Amazon.


Why Not SPIFFE for Pico Identity?

A printed visitor badge and a passport

When I wrote about pico-to-pico identity arriving in version 1.6, I explained why I reached for DIDs rather than KERI. The other obvious question is "Why not SPIFFE, the workload-identity stack that Kubernetes shops already run?" It's a fair question, because a pico is, from one angle, just a workload; it's a running process that needs to prove which process it is before another one will talk to it. So why give it a DID instead of a SPIFFE ID?

The answer comes down to a single property: whether the identity travels with the thing it names. SPIFFE and picos give opposite answers to that, and the opposition isn't an accident. It falls out of what each one is built to identify.

What SPIFFE Gets Right

SPIFFE is a genuinely good design for the problem it takes on. A workload asks the local agent for its identity, and instead of holding a secret it proves who it is by what it is and where it runs; the platform attests to the process, and the workload gets back a short-lived credential called an SVID. There's no long-lived key to leak, because the credential expires in minutes and renews on its own. For a datacenter full of ephemeral, interchangeable containers, that's exactly right; you don't want a Kubernetes pod hoarding a private key that outlives it.

The trust anchor for all of this is a server that runs the trust domain. That server decides which workloads exist, attests to them, and signs their SVIDs, and every workload in the domain trusts it by construction. Inside one administrative boundary that centralization is a feature, not a flaw; someone runs the cluster, and that someone is exactly who should be minting identities in it. SPIFFE fits the shape of the place it lives.

Identity that's Derived versus Identity that Lasts

That fit is also the reason SPIFFE isn't what a pico needs. A SPIFFE identity is derived: it comes from what the workload is and where it runs, and the domain's server mints it fresh in whatever environment the workload happens to land in. Move the workload to a different cluster and it gets a different identity from a different authority, because the identity was never the workload's to carry; it was a fact about the environment. That is a badge the building prints for you at the door. It works beautifully inside the building and means nothing the moment you step outside.

A pico's identity is long-lived by design. Every pico holds its own keys and carries a did:webvh that stays the same identifier no matter which engine it runs on or how long it runs; the identity is a property of the pico, not of the host underneath it. When a pico moves between engines, its identity moves with it, because the pico is the one holding the keys that prove it. That is a passport rather than a printed badge; you carry it across borders, and it still says who you are on the other side. For a system whose whole point is picos and meshes that are portable between engines, an identity that gets re-minted per environment just isn't the right choice.

Durable identity is a property that makes picos useful for tasks that ephemeral workloads can't do easily.

  • Persistent relationships. A subscription links two identifiers; if they reset on every restart, the relationship can't outlive the move. Durable identity is what lets a mesh of relationships accumulate and survive.
  • Reputation and history. Because a pico keeps the same identifier over time, the parties it deals with can remember their history with it and decide how far to trust it. An identifier that resets each session gives them nothing to base that judgment on.
  • Credentials. A verifiable credential is a claim about a subject, and the subject has to persist for the claim to keep meaning anything. Without a durable identity there is nothing to hold or present a credential.
  • Delegation. An actor operating on your behalf needs a stable identity so the authority you grant persists and stays revocable. Ephemeral identity means re-authorizing constantly and having nothing durable to take back.
  • Continuity across infrastructure. Because the keys belong to the pico, the actor is decoupled from the host; you can move engines, change providers, or recover from a crash without losing who the pico is.
  • Longevity beyond any vendor. The identity outlives the company that built the device, so a pico doesn't die when someone's cloud is switched off. This is the Internet of My Things rather than the CompuServe of Things.
  • A lifecycle that follows the thing. For something with a long life that changes hands, identity and history span custodians instead of resetting with each one.

A digital twin is a good example of where durable identity matters. A pico that stands in for an IoT device grows more valuable the longer it lives, because it accumulates the device's history, relationships, and state over years rather than minutes. When I built Fuse, each car had its own pico, and selling the car meant handing that pico to the new owner with the maintenance history and important relationships intact; the identity was bound to the vehicle, not to me. That is the case ownership language gets wrong. The pico's identity outlives any particular owner, and it has to, because the car it represents might too.

Trust Domains and Strangers

The same split shows up when two identities from different places need to trust each other. SPIFFE can federate across trust domains, but it does it the administrative way: the operators of two domains exchange trust bundles ahead of time, and only then can workloads on one side verify workloads on the other. That's reasonable when both domains belong to the same company, or to two companies that signed a contract; someone with authority on each side sets the relationship up in advance. It assumes the parties already have a reason, and a person, to arrange the introduction.

Picos owned by two different people, on two different engines, don't have that person in the middle, and I don't want to require one. A pico resolves another pico's DID and the two form a relationship directly, with no administrator on either side pre-arranging a federation. This is the same first-person idea I keep pushing for human identity, now applied to software actors: identity you present yourself, not identity an authority vouches for on your behalf. Trust between strangers shouldn't require a treaty negotiated by their landlords.

An Actor, Not a Process

None of this makes SPIFFE wrong; it's just built for a different kind of thing. SPIFFE names a process: a unit of execution that runs, does its work, and can be killed and restarted at will, where you care that some process is handling the request rather than which one. A pico is an actor: something that persists, holds state and relationships, and acts for someone or something over time. A process has an identity so the system can manage it; an actor has an identity that it uses over time.

Systems engineers have a mantra for this divide: treat your servers as cattle, not pets. Cattle are numbered and interchangeable, and when one gets sick you replace it instead of nursing it back to health; that is exactly the right way to run a fleet of workloads, and it's the world SPIFFE is built for. A pico is a pet. It has a name and a history, and relationships that make it worth keeping this one rather than swapping in another that would do the same job.

That distinction is the thread running through everything above. Persistent relationships, reputation, credentials, delegation, history, continuity, and longevity are not affordances a process needs; they are what it takes to be an actor rather than a process, and every one of them presupposes an identity that lasts. So a durable identity isn't a feature bolted onto a workload. It's foundational.

The choice between SPIFFE and DIDs, then, isn't really a choice between two identity technologies; it's a question about what you're naming. If you are naming a replaceable process inside one administrator's domain then SPIFFE is the right tool, and I'd use it. But a pico is an actor that persists over time, not a process that happens to carry an identity, and the identity model has to reflect that. Give the thing that's meant to persist and travel an identity that persists and travels with it.


Photo Credit: A printed visitor badge and a passport from ChatGPT (public domain)


Pico-to-Pico Identity Arrives

Two kinds of identity for a pico

Last month I released version 1.5 of the Pico Engine and argued that identity inside the engine is really three problems, not one. A human needs to prove who they are to a pico mesh; an outside app or webhook needs a scoped way into the mesh; and one pico needs to know which pico is calling it and whether to trust it. I shipped the human and third-party layers then and left the harder one for later. Today I'm releasing version 1.6, and that third layer, pico-to-pico identity, is here.

The short version is that every pico now has its own cryptographic identity, and that identity can travel. This is the piece I've wanted for a long time, because it's the foundation for a goal I keep circling back to: picos and whole meshes that are portable between engines rather than pinned to the machine where they happened to be born. Let me describe the shape of it, because the design turns on a distinction that took me a while to get right.

The Layer I Was Waiting to Build

I shipped the first and third layers in 1.5 and held this one back on purpose. Passkeys and OAuth sit on machinery the engine already had: channels, ECIs, and channel policy. Pico-to-pico identity required something a bit more complex. It meant moving DID keys into the engine as a core primitive, pulling a lot of KRL into wrangler, and running pico-to-pico traffic over DIDComm instead of plain HTTP. That's a large change, and it touches much of the engine, so I wanted to handle it separately.

This layer is what makes a pico an actor with a real online presence. A channel identifier tells you how to reach a pico on one engine right now; it says nothing durable about the pico's identity. For introductions between strangers, for encrypted traffic, and eventually for verifiable credentials, a pico needs a stable answer to "which pico is this?" that is portable across engines. That answer is a DID, and in 1.6 every pico has one from the moment it's created.

Two DIDs, Two Jobs

The design I landed on gives each pico two types of DIDs, each with different jobs. The first is a did:webvh, the pico's portable identity. Every pico gets one when it's created, and the engine serves its DID document at a stable URL so anyone can resolve it. Think of it as the pico's passport: it's how a pico introduces itself, and it's what you hand a stranger who needs to know who you are before they'll talk to you.

The second is a did:peer, and there's one of them for every relationship, called a subscription, a pico forms. It isn't provisioned up front; the two engines mint a fresh pair during the introduction handshake. There is a separate pair of peer DIDs for each relationship. Think of it as an email you give to exactly one person. The passport says who you are to everyone; the email is the private line for a single connection, and it means nothing to anyone else.

Subscription developer UI showing webvh DID at the top and peer DIDs in the established subscription
Subscription developer UI showing webvh DID at the top and peer DIDs in the established subscription (click to enlarge)

The developer UI makes the split concrete. The Identity panel at the top of a pico's Subscriptions tab shows its one did:webvh, the passport it hands out, next to the switch that decides whether it accepts unsolicited introductions to that DID. Each established subscription below carries a different pair: the remote party's peer DID and this pico's own peer DID, minted for that one relationship. The subscription's Rx channel is where policy still lives; the DIDs name who the two parties are, and the ECI decides what this one is allowed to do here.

That split matters more than you might think. A single, universal identifier is a mistake I've watched newcomers to identity make for years. Correlatability is a factor, but the bigger payoff is practical: because every relationship has its own identifier, each one can be managed on its own. You can rotate the keys on a single connection, or tear it down and rebuild it, without disturbing any of the others; if a peer DID is ever compromised, the damage stops there and you recover that one relationship in isolation. It's the email analogy again, where changing the address you gave one contact doesn't impact the rest.

How Picos Actually Talk

Two picos that aren't parent and child talk to each other through a subscription, which is just a pairwise relationship with a record on each side. In 1.6 you form one by handing the initiator the recipient's did:webvh as the target; the two picos run the introduction, agree, and store each other's peer DIDs. After that, queries and events flow over the peer relationship. On the same mesh the engine keeps that traffic local; across meshes or across engines it runs encrypted over DIDComm to the peer's address.

DIDs didn't need a new authorization mechanism; they slot into the channel model the engine already had. A subscription's peer DID is its channel, and channel policy governs it exactly as it governs any other channel, so authorization is enforced right where it always was. The DID names who is on the other end of the relationship, and the policy on that channel decides what they are allowed to do. Legacy ECIs haven't gone anywhere either; parent and child picos still talk over family channels named by ECIs, where a full DID would be overkill.

The consequence I care about is what this does for trust between strangers. A pico can choose to accept unsolicited introductions to its public identity, which lets a community pico or a registry take subscriptions from picos it has never met. Two meshes owned by two different people, on two different engines, can form a relationship because one resolved the other's DID and both agreed; no one had to stand up a federation agreement or register with a common broker first. The relationship is the unit of trust, and these changes make it cryptographic and portable.

Why These Methods, Not KERI

Anyone who has spent time at IIW will ask why I reached for did:webvh and did:peer rather than KERI, which answers the same "who is this actor" question with self-certifying identifiers and a key event log that needs no web host at all. KERI has a great design, and on the narrow point of surviving a move it's arguably stronger than did:webvh; a KERI identifier carries no URL that has to stay reachable, which is exactly the loose end I admitted above. So this wasn't a judgment that one approach is right and the other wrong. It came down to what picos already need to do the moment two of them are connected.

That need is messaging, and picos exchange events and queries over DIDComm. Peer dids were built for precisely that job: a pairwise, private relationship identity that DIDComm tooling already knows how to carry encrypted traffic over. Pairing it with did:webvh for the public introduction let me use a messaging philosophy the pico world has used for years since it parallels the DIDComm model. KERI's strengths live mostly in the identifier and its key history; picos needed the identifier and the encrypted conversation that follows it, and the DIDComm path gave me both with the least new machinery. If the day comes when the portability tradeoff bites hard enough, I'd happily revisit that choice.

A Step Toward Portable Meshes

I won't pretend a pico can pick up and move to a new engine today with no loose ends; the engine base URL is still baked into a pico's did:webvh, and making that survive a move is work still ahead. But the hard part, giving each pico a real cryptographic identity and a way to carry its relationships, is now in the engine rather than wrapped around it. That's the foundation portability was waiting on, and everything above it, from moving a mesh between engines to carrying credentials between them, builds on this.

Full portability is the largest gap, but it isn't the only one. The identifiers are in place; the verifiable credentials that ride on them are not, so a pico can prove who it is but can't yet hand another pico a signed claim about what it is or may do. Key management is thin across the board: the private keys behind a pico's DIDs sit in the engine's own store today, when they belong in the operating system's key vault or hardware-backed storage, and rotation and recovery need more work now that a pico's identity is the thing others rely on. Losing the keys shouldn't mean losing the pico. Authorization also still keys off the channel a caller holds rather than the identity behind it, so the natural next step is to let a receiving pico decide based on who is actually calling using a proper authorization engine. Each of these builds on the identity that landed in 1.6 rather than replacing it.

I've spent a long time arguing that people deserve software that acts for them and that they own outright, not a rented seat on someone else's platform. A mesh you can pick up and move provides infrastructure to realize that idea. If your picos can only live on one engine, you don't really own them unless everyone is running their own engines (not likely). Version 1.6 doesn't finish that story, but it lays down the identity it depends on. The next thing I want to do is exercise it in Manifold and find the rough edges by using it. If you want the details, the DID and Subscriptions pages walk through each piece.


Photo Credit: Two kinds of identity for a pico from ChatGPT (public domain)


The Pressure Behind Identity's Diseconomies of Scale

An engineer trying to hold back a high-pressure system springing leaks from every joint

Eve Maler recently unpacked a statistic that is easy to misread. In her post she reports on an IANS Research finding that identity and access management was the only security category with negative economies of scale; IAM takes 8% of the security budget at organizations under $400M in revenue but 14% at organizations over $10B. The obvious reading is that identity gets more expensive, per dollar, the bigger you get. Eve's better reading is that "gnarliness," her word for the tangle that makes identity hard, is multi-factorial, and that company size is a poor proxy for it.

She lists the real drivers: how many jurisdictions you operate in, how large your partner ecosystem is, how many apps you are wiring to an identity provider, how loosely coupled your lines of business are, and whether anyone owns identity strategically. What predicts gnarliness, she argues, is not any single factor but the unique combination your organization lives with. Reading her post, I recognized a shape I had drawn for chapter 19 of my forthcoming book, Authorization in Action. I give the tangle she describes has a name and a diagram.

Gnarliness Has a Shape

In the book I distinguish two things that grow at different rates as a system expands. The first is the decision surface: the total set of situations in which access has to be evaluated. The second is the decision infrastructure: the shared policy, consistent enforcement, contextual signals, governance, and delegation models that let those decisions be made well. The surface expands with more actors, more actions, more contexts, more delegation, and more automation. The infrastructure only expands when someone deliberately builds it.

Decision surface, decision infrastructure, and authorization pressure

The gap between the decision surface and the decision infrastructure is authorization pressure.

When the surface outruns the infrastructure, the gap between them shows up as authorization pressure: the growing difficulty of making decisions consistently, explaining why they came out the way they did, and keeping control as the system scales. Pressure is not a failure of effort; ACME, the company I follow through the book, was improving access control the whole time. Pressure is what you feel when access decisions are being made everywhere and governed nowhere. Eve's drivers of gnarliness map almost one to one onto the things that expand the decision surface; more jurisdictions maps to more context, a bigger partner ecosystem is more delegation, and more apps across more brands is more actors taking more actions.

Why Size Was Never the Predictor

Once you see identity's difficulty as pressure rather than size, Eve's objection to size as a predictor is easy to explain. Revenue and headcount tell you almost nothing about the decision surface. A small, acquisitive fintech operating in a dozen regulatory regimes, wiring together the identity systems of the companies it just bought, can carry far more surface than a giant consumer brand running one simple app for five hundred million users. The first organization is under enormous authorization pressure; the second is barely under any. Size isn't what matters in either case.

That is also why IAM shows up as the category with negative economies of scale while other security categories get cheaper per dollar. The IANS number is not measuring the cost of being big. It is measuring the pressure that accumulates when the decision surface expands faster than the infrastructure meant to govern it, and large organizations have simply had more time and more room to let that gap grow. In other words, the diseconomies of scale are a symptom of authorization pressure, and the pressure itself is what you get when the decision infrastructure falls behind the decision surface. The underlying cause is an infrastructure that never grew to match the surface, not size.

Relieving the Pressure

You cannot relieve the pressure by shrinking the decision surface, because the business is the thing expanding it. Every new partner, every new market, every agent you deploy is simply the company doing what it exists to do. The only durable move is to strengthen the infrastructure so decisions stay consistent, explainable, and bounded even as the surface grows. That means externalizing policy out of application code, evaluating decisions at runtime against relationships and attributes and context, governing the signals those decisions depend on, and making delegation explicit rather than implicit.

This is where Eve's diagnosis and mine reinforce each other most usefully. She notes that the organizations doing well with identity treat it strategically, often under someone she calls an Identity Product Owner, and that unified identity has started pushing downmarket wherever identity turns out to be a revenue multiplier rather than a cost. In the language of my book, those organizations have built decision infrastructure ahead of their decision surface, so the pressure never gets too high. Identity stops being the category that gets gnarlier with size and becomes a capability that lets a company expand the surface on purpose. A gap closed early is the difference between complexity that compounds and complexity you can manage.

The Surface Won't Stop Expanding

Here's the bad news: the decision surface is about to grow faster than it ever has. More interactions are crossing organizational boundaries; more actions are taken by services and agents instead of people; more decisions depend on real-time context that no static role can capture. I have argued in my series on agentic AI and authorization that agents expand the surface precisely because they act over time, under changing conditions, and often on someone else's behalf. The pressure Eve measured in enterprise IAM budgets is the same pressure that will decide whether agentic systems are governable at all.

That is the human stake underneath the budget line. Authorization is how we govern the ways authority gets exercised, by our people, by our partners, and increasingly by the software acting for them. When the pressure is high, people confront a digital world of inconsistent permissions and unexplainable denials, a world where no one can say why the door opened or stayed shut. When the infrastructure keeps pace, authority is legible and bounded, and people can act with confidence inside clear limits. Eve is right: gnarliness is multi-factorial and size is the wrong thing to measure. What we should measure instead is the pressure between the decisions we now have to make and the infrastructure we have built to make them well. That pressure is something we can manage.


Photo Credits: Under Pressure from ChatGPT (public domain) and Decision Surface and Decision Infrastructure, from Chapter 19 of Authorization in Action (Manning)


A Map of the Manifold Environment

Emil Sotirov wrote after my last few posts with a good request:

Would you, please, do a map/diagram of the whole environment you're describing, giving an idea about the functional capabilities?

That's a fair thing to ask. I have described this environment across three posts now, a piece at a time, and never in a single picture: the platform rebuild in Manifold API and Sensor Network, the engine's new identity layer in Identity for the Pico Engine, and the interface in Using Home Assistant with Manifold.

The Manifold environment, from the pico engine to Home Assistant

The figure above puts the whole thing in one place and labels what each layer does:

  • Pico engine—hosts the picos and supplies, among other things, identity: passkeys for the owner and OAuth for outside software. One engine can run several independent meshes at once, as shown in the figure.
  • Pico—the actor. Each pico is an independent, addressable entity with its own state, its own rules, and its own channels, and it interacts with other picos only by exchanging events. Everything above this layer in the diagram is running on picos.
  • Wrangler—the pico operating system. It gives each pico its channels, children, and subscriptions, and it is the machinery every higher layer calls to create picos and wire them together.
  • Manifold—the framework layer, responsible for mesh lifecycle and notifications. It controls a mesh comprising a root pico, a Manifold pico that creates and tracks things and communities, all the things and communities, and tag and skills registries. It fans alerts out to various channels. Everything above delegates that work to Manifold rather than building it again.
  • Sensor network—a domain layer that specializes the generic platform. It treats communities as sensor groups and things as LoRaWAN devices, decodes their payloads, and raises threshold alerts back through Manifold's notifications.
  • Home Assistant—the interface, where a person actually sees and drives everything: devices, dashboards, and automations. The Manifold hub integration authenticates over OAuth and renders things and communities as Home Assistant devices, and a companion integration adds sensor entities for the domain layer beneath it.

The figure shows a classic delegation stack: each layer leans on the one beneath it and adds capabilities the layer below does not have. The one thing the figure hints at but does not yet deliver is the pair of light links between meshes, marked x and y. Those cross-mesh relationships are waiting on the pico-to-pico identity layer that is still ahead, which I will cover in its own post. That aside, this is the whole environment in a single picture.


Using Home Assistant with Manifold

A Home for Your Pico Mesh

The original Manifold (which was a replacement for the old SquareTag) gave a person a place to gather their connected things under their own control, but it needed its own web application to provide the UI and manage accounts. Rebuilding Manifold on version 1.5 of the pico engine turned it into a framework for building meshes of picos. But that mesh is only useful if outside software can reach it, if the owner has an interface that is easy to use, and if specialized domains can extend it without forking the platform. Those are three separate problems, and a Home Assistant integration was how I proved I had an answer to each one.

This work sits directly on top of the last two things I wrote about. In Manifold API and Sensor Network: Two New Repos I rebuilt Manifold as a framework and rewrote the sensor network as an example that runs on it, and I flagged a Home Assistant integration as the obvious next step. Then in Identity for the Pico Engine I added OAuth to the engine and said the Home Assistant layer would be the first real exercise of that identity work. This post is where those two threads meet.

I'll take them in the order they build on one another: an OAuth workflow that lets an outside application into the mesh, Home Assistant replacing the custom Manifold interface, and a pattern that lets a domain like a sensor network add its own behavior on top. Each of the three are working now. One thing still doesn't, and I'll come to that.

Letting an Application In

Version 1.5 of the pico engine finally moved identity into the engine itself, including OAuth for external applications and webhooks; I described that design earlier in Identity for the Pico Engine. Home Assistant was the first real client I pointed at it. When someone adds the Manifold integration, Home Assistant runs the OAuth flow and comes away with a token it can use to access the mesh. This allows each mesh owner to grants access deliberately using a token that is scoped to what the application should see, and that the owner can revoke later.

An Interface I Didn't Have to Build

The old Manifold answered the interface question by building a web application: accounts, dashboards, notification screens, all of it written and maintained as custom code. Home Assistant already solves that problem for a large community of users, and its open source. So rather than ask owners to learn another dashboard, Manifold now appears inside one that many of them already run.

Things and communities show up as Home Assistant devices, and Manifold's notifications reach the owner through a dedicated channel that the homeassistant ruleset creates on install and forwards enabled alerts to. Home Assistant is already where many people run their home automation and sensors, and a Manifold mesh drops into that same surface, adding picos to HA, each with its own logic and its own relationships. Reusing a mature system beats maintaining a thinner copy of it. The time I would have spent on yet another dashboard goes to other projects.

Manifold Dashboard showing Safe & Mine and Journal controls
Manifold Dashboard showing Safe & Mine and Journal controls (click to enlarge)

Room for Specialized Communities

A platform is only generative if other people can build on it without asking permission, and the third component demonstrated that idea. The sensor network I rebuilt as a Manifold example needed sensor-specific behavior in Home Assistant, not just the generic view of things and communities. So it ships a companion integration, pico_mesh_sensor_network, that declares the Manifold hub as a dependency and attaches sensor entities to the thing devices Manifold already created. The pattern is small: domain rulesets in the repo root, a companion component beside them that depends on the hub, and a stable surface to import from. Any Manifold community can follow it, which is exactly what I wanted to demonstrate.

What Still Doesn't Work

One piece of the old Manifold has not made the trip yet. SafeAndMine, the application that started this line of work, depended on physical tags: an NFC sticker or a QR code on an object that resolves through a tag registry to the pico that represents that thing. The registry is in place and things can register against it, but scanning a tag and following it to the right pico does not yet work end to end. Until that path is solid, Manifold can model your things but it cannot let a stranger scan the tag on your lost backpack and reach you. That is the next thing to finish.

Manifold has evolved from a product with its own screens to maintain into a foundation for building meshes of picos that can sit at the network edge. What makes that real is the architecture holding together: identity that lets outside software in on the owner's terms, an interface in a system people already trust, and an extension pattern that invites other domains to build. The tag path still has to land before I would call the old Manifold fully replaced. But the important parts are working now.


Photo Credit: A Home for Your Pico Mesh from ChatGPT (public domain)


Identity for the Pico Engine

Protecting your pico mesh

Today I'm releasing version 1.5 of the Pico Engine. The primary features in this release are support for accounts, authentication to the UI via passkeys, OAuth client credentials for channels used as webhooks, and optional OAuth Authorization Code Grant credentials for any given pico mesh. If you know me, you might be thinking "wait you've been working on picos and identity for 25 years and you're just getting around to bringing them together?!?" There's a story there.

The original pico engine (what we call the "classic" pico engine) was begun in 2008. In that era of Infrastructure and Platform as a Service models, we'd have been silly to build a product that didn't support identity and accounts. And we did. The classic pico engine, written in over 400,000 lines of Perl as an Apache module, has a full-blown identity system with passwords, accounts, and OAuth support. When we rewrote it (after the demise of Fuse) we were looking for something less of a platform and more personal. The new engine was implemented in Node and mainly used locally or in small experiments. Even as it grew and we started using it for more significant efforts like Manifold, we just wrapped it in an identity layer written separately.

But I've got some projects in mind that need proper identity to work and so the time has come to bite the bullet and add identity to the pico engine itself. Let me tell you about the architecture and what I'm releasing today.

Three Kinds of Identity

The first thing to get straight is that identity here isn't one problem. It's three. They are easy to lump together, but they ask different questions and want different answers. When I open the engine's UI, the engine needs to know it's talking to me. When one pico calls another, the pico on the receiving end needs to know which pico is calling and whether it's allowed to do what it's asking. And when something outside the engine, like Home Assistant or an inbound webhook, hits the public API, the engine needs to know who that caller is and what it can do. Keeping these three apart is what keeps the whole thing from turning into a tangle.

Each one has a natural answer:

  • Human to pico mesh. You sign in to your root pico with a passkey. Each root pico is its own WebAuthn relying party, so there's no shared password and no central table of users. Once you're signed in, that root pico acts as the controller for the entire mesh.
  • Pico to pico. This is the layer that gives a pico its own portable, cryptographic identity using DIDs and DIDComm to provide mutual authentication. That identity can survive a move from engine to engine, and it lets two picos from different meshes trust each other without anyone setting up a federation agreement first.
  • Third-party access. A webhook or an app can't use my passkey session, and I don't want it holding a bare URL that works forever. So it gets an OAuth token instead, one it has to ask for and one I can take back.

I'm building these as three layers, and I shipped the first and third in 1.5. That order probably looks backwards, so let me explain it. The pico-to-pico layer is the most interesting of the three, but it's also the most work. It means moving DID keys into the engine as a core primitive, pulling a lot of KRL into wrangler, and eventually running pico-to-pico traffic over DIDComm instead of plain HTTP. That's a big change, and it touches a lot of the engine. The other two layers don't need any of that. Passkeys and OAuth sit on top of machinery the engine already has: channels, ECIs, and channel policy. So I could add human sign-in and third-party access now, and leave the deeper identity work for when I can give it the attention it deserves.

No Usernames, No Passwords

One decision inside the human-to-mesh layer is worth pointing out: there are no usernames and no passwords anywhere in the engine. You register with a passkey and you sign in with a passkey, and that's the whole story. There's no email-and-password form to fall back on, no step where you make up a username, and no password database sitting on the engine waiting to be leaked. When you register, the engine creates your account and your root pico and ties them to a passkey your device holds. That is the account.

Part of the reason is that passwords carry problems I didn't want to inherit. They get reused, phished, and stolen in bulk, and every system that stores them becomes a target. Passkeys sidestep all of that: the secret never leaves your device, there's nothing shared for an attacker to steal, and signing in is a touch or a PIN rather than something you have to remember. But the bigger reason is that I think passwordless authentication is where things are headed, and I wanted to build something with no passwords at all and explore how that works. It's easy to bolt passkeys on next to a password form as one more option; it's more interesting to commit to them as the only way in. The cost is that the engine leans entirely on the passkey, which is part of why recovery is such a sharp edge, and I'll come back to that below.

As an initial experiment, I'm pretty happy with it. Logging into different meshes is quick and easy. My password manager (1Password) lets me easily choose between different meshes, and not having to type in a username is great. A passwordless user experience is definitely a better user experience.

Webhooks: Client Credentials

The simplest kind of outside access is one machine talking to another: a webhook that posts an event to a single channel. This is a common pattern that I use frequently. For example, the sensor network that monitors the temperatures in the pumphouse at my cabin gets an event via a webhook from a Helium console.

Since a webhook only ever hits one channel, its credential should be scoped to one channel too. That's a good fit for the OAuth Client Credentials grant. You create a channel for the webhook and tag it oauth-webhook. The channel's ECI becomes its OAuth client id, and you create a secret for it from the Channels tab in the UI. The secret is shown once and stored hashed. The sender trades that secret for a bearer token at /oauth/token, then includes the token on every post to the channel's /sky/ URL.

Client Credentials UI for a Channel
Client Credentials UI for a Channel (click to enlarge)

Two small decisions are worth noting. The first is that the access token is a real token, not the ECI itself. The old server used to hand back the ECI as a shared secret, which mixed up the pico's address with the secret you need to reach it. Now the ECI stays in the URL, where routing needs it, and the token is a separate secret you can revoke on its own. The second is that tagging a channel oauth-webhook locks it right away. Any request without a valid token for that exact channel is turned away before channel policy even runs. Both decisions are about limiting the damage if something leaks. A webhook URL on its own is now useless, and even a stolen token only opens one channel.

Real webhook senders make this less tidy. Helium and Stripe, for instance, post to a fixed URL and will never call /oauth/token to get a token. For them, the bearer requirement still protects against someone discovering the URL, but it doesn't verify that the payload actually came from Helium. That job usually falls to an HMAC signature, and I haven't built that in here. Client Credentials is aimed at senders that can send an Authorization header. The fixed-URL senders are a separate problem for another day.

Whole-Mesh Apps: Authorization Code

The other kind of outside access is an app acting for a person across a whole mesh. The example driving the design is Home Assistant sitting in front of a pico mesh. A single channel is the wrong unit here, because the app needs to read and drive many picos under my root, not just one. So this uses the Authorization Code grant with PKCE, scoped to a root pico and everything under it. The flow is the ordinary OAuth dance. I register the app, which gets its own opaque id. The app sends me to /oauth/authorize, I sign in with my passkey and approve a consent screen, and the app trades the resulting code for a token it uses on any /sky/ event or query channel. Refresh tokens allow for rotation, and the access tokens are the same opaque bearers as the webhook case. The only difference is that they're checked against the whole mesh instead of one channel.

OAuth App Registration in the Settings Panel
OAuth App Registration in the Settings Panel (click to enlarge)

OAuth isn't required on every mesh and an engine-wide switch would be wrong, because one engine can now host several independent roots that belong to different people. So the switch is per mesh instead. You install an optional Wrangler ruleset, io.picolabs.oauth, on the root pico. Once it's there, every outside call to that mesh's /sky/ endpoints has to carry a token. Leave it off and the mesh works the way it always has, under channel policy, with the one exception that oauth-webhook channels are always locked. That means one engine can run a locked-down mesh and an open one right next to each other. The engine still does the real work, holding the tokens, running the ceremony, and serving the routes. The ruleset just marks the mesh and carries its OAuth settings.

Both grant types can live in the same mesh without getting in each other's way. They share one token store and one check, which just looks at what kind of token it is. A Client Credentials token is tied to the ECI in the URL. An Authorization Code token is checked against everything under its app's root. Because the two are separate, revoking Home Assistant's access leaves the webhook credentials alone, and revoking a webhook leaves the app alone. This lets a pico grant access to different services for different reasons.

Tradeoffs and What's Next

This release makes a few deliberate choices that limit what the engine will do, and they're worth being explicit about rather than leaving for you to trip over. The first is that there's no admin. Each mesh has a single owner, and that owner is simply whoever holds the passkey. If you lose track of your passkey, there's no recovery and no back door that lets you in anyway. That's a hard edge, but it keeps the model simple, and it fits the pico ethos, where a pico is something you own outright rather than an account someone else grants you. It may not be enough for someone who wants to use the engine as the root of a user-facing system, where ordinary users expect a way to recover a lost login. That's a fair worry, and one I'll come back to.

For now the engine also assumes one owner per mesh. That owner can register more than one passkey, so a laptop, a phone, and a hardware key can all open the same mesh; "one owner" doesn't have to mean "one device." I expect to relax the single-owner rule down the road, but I wanted to start simple. And while the engine is multi-tenanted now, meaning one engine can host meshes belonging to different people, it doesn't let just anyone sign up and create one. By default, new meshes come through an invitation from an existing owner. You can turn self-signup on if you want an open system, but off is the default.

Using the root pico as the entry point for all of its descendants is powerful. Signing in once gives you a handle on a whole tree of picos, and everything under the root inherits from that single point of control. But I want to be careful about what that does and doesn't buy you. None of these changes automatically makes an engine or a pico mesh secure. Passkeys, OAuth, and channel policy are tools, not guarantees. A builder can still open a channel too wide, hand out a token that never expires, or run the engine on a host that isn't locked down. What I've tried to do is give builders the pieces they need to move in a secure direction, with defaults that don't fight them along the way.

All of this passes the tests I've written, but I'll be honest that I haven't put it in front of a real use case yet. Tests tell you the machinery works; they don't tell you the design holds up when someone actually leans on it. The next thing I want to build is a Home Assistant layer for Manifold-based pico meshes, and that will be the first real exercise of this identity work. I expect to find the rough spots that way, and I'd rather learn them by using the thing than by guessing at them now.

Who Gets In

I've spent a long time arguing that people should have a personal cloud (to use an antiquated term). By that I mean software that acts for you, that you control, and that isn't just a rented seat on someone else's platform. The pieces in this release line up with that idea. A passkey proves you're you. Your root pico gives you a mesh of your own out in the world. And OAuth lets you lend that mesh's capabilities to the tools you choose, on terms you can revoke whenever you like. The piece still missing is the pico-to-pico layer, the one that will let a pico move between meshes and let two meshes trust each other without anyone in the middle. That work is still ahead. What I'm releasing today is the part that lets you walk up to a pico engine, prove who you are, and start working in a mesh that is unmistakably yours. If you want the nuts and bolts, the Identity System documentation walks through each piece.


Photo Credit: Protecting your pico mesh from ChatGPT (public domain)