The Workshop — Lyra's Tool Architecture

A long-form narrative tour of the Roxabi Factory tool system — from the five-layer panorama down to a single message travelling from keyboard to reply.

Version 1.0 · Updated

01

Why We Are Here

Before pushing the door open, take a moment to look at the current state of things. For several months now we have been talking about tools. We have built them, taken them apart, redesigned them. In every conversation, the word tool has slipped from one reality to another: sometimes a Python function an agent invokes directly, sometimes a NATS service running in the background on a different machine, sometimes a Quadlet sidecar waiting for requests, sometimes a skill the model learns to orchestrate without even knowing it is doing so. Four design spaces have been living side by side without quite speaking to each other.

It is like a workshop where four craftspeople work in the same room, each at their own bench, each with their own dialect for naming the same objects. As long as everyone stays in their corner, it holds. But the day one of them asks the other for a hammer, you discover they are not pointing at the same thing.

What follows is the floor plan of the workshop. Not a new drawing — just the clean version of what already exists, reframed so we speak with one voice. We will climb to the mezzanine, take in the whole view, come back down object by object, open the doors, follow the flows, examine the locks. By the end you should be able to pick up any piece and know precisely where it belongs, what it touches, and what it is for.

This text invents nothing. It puts upright what already exists — a common language, from built-in to sub-agent, without drift.

02

The Panorama

Come up to the mezzanine with me, two metres above the floor. From here the workshop reads as five stacked layers. Not five rooms side by side — five layers resting one on top of the other, like a geological cross-section. Each layer rests on the one before it; each layer serves the one that follows.

At the very bottom, the identity layer. This is where the marks are laid — who this agent is, which group it belongs to, which tools it has the right to touch. This layer is physical: it materialises as configuration files on disk, as authentication keys mounted like slipping a key into a safe, as named volumes that partition the territory. Without this layer, nothing has identity; everything floats.

Just above, the harness layer. The harness is the living envelope that contains the agent's loop. It takes the prompt, passes it to the model, catches the tool requests, executes them, returns the results to the model, and repeats — until the agent says I am done. The harness holds only one thing at a time: the memory of the current turn. Everything else — the long history, shared data, heavy files — lives elsewhere.

Higher still, the tool layer. This is the shelf where the agent comes to pick what it needs. Four categories of tool sit on that shelf side by side: tools that fit directly in the harness's hand, tools it calls at a distance by message, tools that chain several others into a deterministic sequence, and tools that are in reality other nested harnesses. We will come back to this in detail — it is the densest section.

Above that, the shared contracts layer. This is the common language. Every piece of the workshop imports these contracts: the definition of what a tool is, the shape of a result, the structure of a manifest. Without this layer, every craftsperson falls back into their own dialect — and that is exactly what we are in the process of correcting.

And at the very top, the model. It looks over everything from above. It only sees the surface: the list of tools handed to it, their descriptions, their parameters. It does not know, and does not need to know, that one tool sits in the harness's palm while another is ten metres away at the end of a cable. For the model, it is the same handle.

Five layers, readable bottom to top. Each does one thing, does not overflow its boundary, and rests cleanly on the next.

03

The Harness

Come back down. Push this door — the one in the middle, marked harness. This is where the agent lives when it thinks.

Inside, it is surprisingly simple. At the centre of the room, a loop. The harness receives a complete prompt, sends it to the model, waits for the response, looks at what the model is asking it to do. If the model wants a tool, the harness goes and fetches it from the shelf, waits for the result, gives it back to the model, and the loop continues. It turns until the model decides there is nothing more to do — what it calls an end_turn. At that moment the loop closes, the harness yields control, and the turn is over.

While the loop is turning, the harness holds only one thing in hand: the memory of the current turn. Which tools it has already called, which results it has already received, at what stage of the conversation it stands. This memory is deliberately ephemeral. Once the turn ends, it is discarded. The harness keeps nothing.

This matters because we often confuse the roles. Everything that must survive the turn lives elsewhere. The long conversation history is stored by the hub, which knows who spoke to whom and when. Heavy artefacts — images, audio files, everything that weighs — are deposited in the blobstore, and only their references travel. The durable knowledge of an agent — its notes, preferences, traces — lives in its own volume on disk. The harness, by design, is amnesiac. That is precisely what makes it interchangeable.

There is one other dimension to understand: there is only one harness binary. One. The same container image, the same code, everywhere. What differs from one agent to another is never the harness code — it is the configuration at instantiation time. Same body, different identities.

04

The Agent as an Instance

How does that single harness become five distinct agents? This is where we touch the most elegant pattern in the whole architecture.

Quadlet — the Podman tool that manages our containers under systemd — natively supports a notion called the instance template. In practice, you drop a .container file with an at-sign in its name: factory-agent@.container. That is not a functional container per se — it is a mould.

When you want an agent to come alive, you tell systemd to start factory-agent@telegram.service. systemd reads the mould, replaces the at-sign with telegram wherever it appears, and produces a concrete instance. The mounted volume is no longer ~/.roxabi/factory/agents/ — it is ~/.roxabi/factory/agents/telegram/. The environment file is no longer env/.env — it is env/telegram.env. The NATS secret is no longer factory-nats- — it is factory-nats-telegram. Everything resolves cleanly from the at-sign.

If tomorrow you want a Discord agent, a GitHub bot agent, a personal assistant agent, you start factory-agent@discord.service, factory-agent@gh-bot.service, factory-agent@assistant.service. Each instance uses the same image, the same harness binary, but inhabits an isolated territory. Its own list of authorised tools. Its own system prompt. Its own secrets. Its own data on disk.

The image to hold onto is the madeleine mould. One mould, several impressions, each unique but baked in the same oven with the same batter. The isolation is physical: one agent cannot read another's volumes, cannot sign with another's key, cannot impersonate another. But you do not pay for binary duplication. One harness to maintain for all; a distinct identity for each one.

Everything that truly decides what an agent can do — its persona, its tool list, its model, its tone — lives in the environment file, on disk, versioned in git, auditable by anyone who opens the repo. Readable, traceable, revocable with one commit.

05

Four Tool Layers

On these two primitives — the looping harness and the message bus — we can now set the tools. And this is where the architecture becomes genuinely interesting, because it is at once simple on the surface and stratified in depth.

Come close to the shelf for a moment. What you see is a row of objects that look alike. Each one has a name, a description, a parameter outline. For the agent reaching out, they are interchangeable in gesture: it grasps the name, passes the arguments, waits for the result. But if you turn one of them over and look underneath, you discover that the transport varies completely from tool to tool. This is what I call the uniform surface over a heterogeneous base — and it is the heart of what you need to understand in this section.

L0a — what fits in the palm. The first layer, L0a, is the bottom of the shelf. These are the built-in tools, compiled directly into the harness binary. When the model decides to run bash, or read a file, or call web_fetch, or publish on a NATS subject, or invoke the gh tool — there is no discovery, no network call, no IPC. The code executes in the same process, alongside the dispatcher, in shared memory. Latency is near zero. You hold the tool in your palm, literally. This group is deliberately small: bash, file_read, file_write, web_fetch, nats_publish and gh. Six primitives. Each does one thing and does it fast.

L0b — what is within reach of the wire. One step further along the shelf, you find L0b. To the eye, these tools are identical to the previous ones: same name, same description, same parameter shape. The agent's hand grasps them exactly the same way. But the difference is under the surface, in the transport. L0b groups the remote tools — voice (its two faces: TTS and STT), image generation, the LLM, Postiz, XCLI. Each of these tools lives in its own process, often in its own Quadlet on a separate machine. To reach them, the harness sends a message on a NATS subject. It waits for the reply. The result travels over the network before it lands. And here is the point worth hammering: the model never sees the difference between L0a and L0b. Ever. For it, bash and voice.tts have exactly the same weight, the same texture. The transport — in-process or via NATS — is handled in silence beneath the surface.

L1 — the choreographed sequence. Go up one level. L1 is what we call a macro tool. It is always presented as a single tool to the agent — one handle, one name, one description. But behind it, it executes a deterministic sequence of lower-level tools without ever going back through the model between steps. Take the concrete example that crystallises this best: vault.add_from_url. Give it a URL, and it does three things in order — fetches the page (scrape, an L0b call), summarises it (llm.summarize, another L0b), stores the result in the vault (vault.add, L0a). Three steps, one visible gesture from the outside. The agent does not have to orchestrate these steps itself; it delegates the sequence to the macro tool, which runs it deterministically. The chain is coded, tested, reproducible. The model delegates the choreography to something more reliable than itself for this specific task.

L2 — the partition slipped into the prompt. L2 is of a different nature. It is no longer a tool invoked at runtime. It is an instruction injected into the system prompt before the conversation even begins. A skill — in the SKILL.md format, following the Anthropic convention — is a score. It does not add a new tool to the list; it teaches the model how to chain the L0 and L1 tools that already exist, within a particular domain. A skill for vault management tells it how to combine web_fetch, vault.add_from_url, and a series of checks without those rules needing to be stated each turn. The logic is laid down once, upstream, in the text of the prompt. To the agent, L2 is invisible as a distinct layer. It simply thinks better in that domain.

L3 — a harness calling another harness. At the very top of the shelf, where the objects weigh the most, sits L3. The sub-agent. Again, the agent parent sees a handle, a description, parameters. But when it grasps this tool, what it triggers is a complete second harness — with its own turn loop, its own context, its own set of tools. This child harness works in isolation, accumulates its own traces, returns a result and stops. The parent sees only the final summary. It perceives neither the depth of the recursion, nor the number of turns the child required, nor the tools the child called along the way. This is the most powerful and most costly layer. Reserved for tasks that truly merit their own workspace — long investigations, multi-file code refactors, analyses that themselves mobilise a palette of tools.

COMPOSITION ↑ L3 — Sub-agent nested isolated harness · returns a summary upward L2 — Skill instruction in the system prompt · teaches domain sequencing L1 — Macro deterministic chain of primitives · no second model pass L0b — Remote atomic satellite on the NATS bus · heartbeat-discovered L0a — Built-in atomic compiled in-process · always available UNIFORM DISPATCH
Four layers, one dispatcher. From a built-in primitive to a recursive sub-agent, every tool passes the same access-control gate and returns the same result type — only the transport changes underneath.

Step back and look at this shelf as a whole. All four layers have the same visible outline for the model: a name, a prose description, a JSON parameter schema. The model has no sensor to distinguish what will run in memory from what will cross the network. The abstraction is total on the model side; the complexity is entirely carried by the dispatcher — that silent switchboard that reads the tool type, checks the rights, validates the schema, and decides the transport without consulting the model.

06

Worker Is Not Tool

Before going further, there is a distinction the architecture defends carefully — because confusing it costs dearly in deployment and in mental clarity: a worker is not a tool.

Look at the hands. When a carpenter hands over a hammer, you do not confuse the hand and the hammer. The hand is what holds, selects, makes available. The hammer is what you grasp to strike. A worker is the hand. Tools are the objects it holds out.

Take imageCLI as a concrete example, because it makes the thing very tangible. imageCLI is a single worker — a single deployed unit, a single process running backstage. And yet it exposes several distinct tools: generate an image, list available engines, cancel an ongoing generation. Three different gestures, three objects in the hand. But one hand. The model, when it decides to act, never sees the worker. It sees the tool — the object held out, not the hand holding it. The worker stays backstage, invisible to the model, silent behind the curtain.

This distinction has a very concrete consequence at deployment time. You do not deploy one container unit per tool — that would be absurd, like ordering a whole workshop for each wrench. You deploy one unit per worker: one Quadlet .container file, one systemd service, one thing to start, monitor, restart. One worker, several tools, one unit. The granularity of deployment is that of the worker, never that of the tool. If imageCLI gains a fourth tool tomorrow — say, inspecting the metadata of a generation — nothing changes in the infrastructure: the hand is already there, it simply holds out one more object.

The model sees a clean surface. The backstage is neat. A worker, not a tool — one unit, many tools, deployed once.

07

The Invisible Boundary

There remains a tension to resolve, and it is less obvious than the previous one. Some tools are built-in — they live in the harness binary, under the palm, ready to respond without any network round-trip. Others are remote — they wait at the end of a NATS subject, behind a worker that might be running on another machine. These two categories might seem to deserve different treatment. The engineering instinct says: two paths, two switchboards, one logic per type.

The Factory says no.

The dispatcher — the switchboard that executes tools — is uniform. When a built-in tool is called, and when a remote tool is called, the invocation gesture on the agent side is rigorously identical. Same access control, same result format, same visible surface for the model. Only the transport changes underneath: one executes in memory, the other goes over the network. But this difference is a plumbing detail, not a surface distinction. The agent does not know, and does not need to know, whether the tool it just invoked was under its palm or at the other end of the line.

This approach draws from two reference points: Claude Code, which normalises tools behind a stable interface regardless of origin, and smolagents, which pushes the same idea — one tool registry, one execution path. The common point between both is that they recognised the internal/external boundary is real for infrastructure — deployment, latency, observability — but must not surface to the model's cognitive layer.

The rejected alternative is what Codex CLI does: built-in and external go through two separate paths, two switchboards, two pipelines. That seems logical at first glance. But it means two security pipelines, two entry points for access rules that can potentially diverge, twice the error surface to maintain. When a rule changes, you change it in two places. When an audit runs, it must cover both paths. The cost accumulates silently, and you only really see it when the two pipelines start to drift apart.

08

Shared Contracts

What makes the uniform dispatcher possible is not magic: it is a common floor, poured under everyone's feet before the first tool was ever written.

This floor is made of two slabs, each with its own role.

The first is roxabi-contracts. It is a contracts module, a sub-package of the workspace that lives in packages/roxabi-contracts/. It carries the type definitions that all tools import: the definition of a TTS request, the structure of an image response, the schema of a unified error, the NATS subjects that serve as official names on the network. Every tool that wants to speak to the Factory draws from this same registry, hub side and satellite side alike. A field renamed in the contracts immediately becomes a type error in both camps — the silent disagreement between a writer and a reader, that classic trap, is transformed into a visible error before the code ever runs. The contracts also carry behavioural hints: this tool is read-only, that one is idempotent, this other is destructive. The hub reads them to decide how to behave in the face of a failure.

The second slab is roxabi-nats, the other sub-package, in packages/roxabi-nats/. Here lives the plumbing: the adaptor that plugs a tool into the NATS network, the middleware that propagates the agent's identity all along the path, the registry client that keeps an up-to-date list of live workers via regular heartbeats. This is pure transport, with no knowledge of Factory subjects or business domains. It does not know what it carries. It only knows how to carry it safely.

Two distinct bricks for two distinct reasons. Contracts evolve when a domain changes shape — a new request, a new field. Transport evolves when the network mechanics change. Mixing them in a single package would force satellites to take plumbing updates every time a voice contract gets a new field, and vice versa.

Without this floor, every satellite rewrites the same twenty lines. The N×M drift — the number of hub-satellite pairs multiplying the surface of potential disagreement — is addressed at the root. One shared source, imported by all.

09

How Data Flows

Now that the floor holds, look at how data moves through this workshop. It is not a single stream — it is several distinct watercourses, each shaped for what it carries.

The territory on disk is organised in three levels of isolation. There is first what is shared read-only across several tools: HuggingFace model weights, for example, which cost dearly to download and have no reason to exist twice on the same machine. One copy, multiple consumers. Then what belongs to a specific tool, set in ~/.roxabi/<tool>/ — its own space, its desk, its working data. Inside that space, an agents/<id>/ sub-directory isolates each agent's memory individually. Three levels of nesting: the shared, the tool-specific, the agent-specific. Each has its reason to exist; each has its boundary.

For heavy artefacts — audio files generated by voice synthesis, images produced by imageCLI, incoming attachments from messaging platforms — there is the blobstore. It is a dedicated HTTP service, factory-blobstore, running on the hub machine in its own Quadlet container, listening on port 8449. Think of it as the workshop attic: you deposit bulky things there and return with a label. That label is a reference — a URL, a content identifier — that travels in NATS messages in place of the raw bytes. The raw bytes never traverse the message network. The NATS message says "the audio file is over there"; it does not carry it. This principle holds for voiceCLI, for imageCLI, for any tool that produces or consumes weighty artefacts.

The durable session memory lives elsewhere again. It rests in a key-value store hosted on JetStream — the persistent message bus that underpins NATS. This is the safe: what is deposited there survives a hub restart, an adapter reconnection, a brief network outage. The conversation does not fall if the process falls.

The harness holds only one thing: the memory of the current turn. What the agent is currently doing, the context of that single interaction. Once the turn is complete, this memory is discarded. Ephemeral by design, so as not to accumulate what no longer needs to be held.

The golden rule: NATS for small structured messages that must travel fast; the blobstore for what weighs and does not deserve to clog the message network; JetStream KV for what must survive between sessions. Three watercourses, three natures of data, three destinations.

10

The Pulse

You have seen the watercourses — NATS for structured messages, the blobstore for heavy artefacts, JetStream for what must survive. But these watercourses do not flow in silence. There is a rhythm beneath all of it, a regular pulse running along the pipes that you can feel under your fingertips if you know where to rest your hand.

This rhythm is the heartbeat. Each remote tool — the voice synthesis worker, the image worker, the LLM worker — publishes at regular intervals a pulse on a dedicated subject: factory.voice.tts.heartbeat, factory.llm.heartbeat, factory.image.heartbeat. This is not a declaration, not a report — just the pulse, the fine wave you see passing through the registry of live workers. The hub catches it, notes it, updates its map. As long as the wave arrives, the worker is there. If it stops, the silence itself is information.

The main flow of work follows another path. When the hub wants to run a model, it deposits its request on factory.llm.generate.request. When it wants to synthesise voice, it pushes to factory.voice.tts.request. The request heads toward the appropriate worker, and the reply comes back via a personal inbox — what NATS calls an inbox, a reply address slipped inside the request that the worker uses to send its result directly back to the caller. The pattern is called request-reply: one question, one answer, one clean and traceable round trip. No blind broadcast, no polling loop.

For the harness — the execution loop that drives agent turns — the same principle holds. It publishes its request on factory.harness.turn.request; the hub listens, receives the wave, takes over. A named subject, a known address, a kept convention.

There is one more thing to see. When an agent wants to know how to use a tool — what parameters, what API, what it accepts as input — it does not need to consult external documentation. NATS Micro exposes a discovery convention under the $SRV.INFO prefix. The agent sends a request; the tool's manifest comes back on demand. Nothing static, nothing compiled in advance. The topology is live, and you can read it by touching it.

One protocol for what flows fast and light; one for what weighs. HTTP appears at one point only — the blobstore. Everything else travels by NATS subjects.

11

Locks and Keys

Now that we have seen the wave, look at the passages. Not everyone can go everywhere in this workshop. There are doors, locks, keys — and they are placed carefully, because negligence here has a visible cost.

The first decision is the grain of identity. You could give a key to each agent — one NATS account per agent, one NKey per instantiated model. With ten agents in circulation, that would mean ten locks to cut, distribute, and revoke. Disproportionate for a marginal gain. The choice is different: one identity per role. The hub has its key. The voice-TTS worker has its own. The image worker has its own. Infrastructure roles — stable, countable, administrable by hand if needed.

The key itself — the NKey, that cryptographic signature that proves you are who you say you are — is stored as a Podman secret, mounted as a file in the container via a tmpfs. type=mount, in Quadlet parlance. Never an environment variable, never a value in a variable that any sub-process could read by inspecting its own environment. The file is placed at a precise location, read at startup, and that is that. The key does not travel — it is stored in its safe and used in place.

The identity of the calling agent, on the other hand, travels differently. It is not the network key that carries it, not a protocol header that NATS would read and interpret. It is a field in the JSON body of the message, an agent_id field slipped into the contract envelope. This choice has a precise reason: touching the transport layer to inscribe application-level information creates a coupling that is hard to evolve. The JSON body belongs to the application layer — it can be evolved, versioned, extended according to contract versioning rules. The caller's identity stays where it is readable by those who need it, without clouding the plumbing.

The last piece of this mechanism is the entry rule. Everything is forbidden by default — this is the deny-first principle, visible in the auth.conf file: default_permissions with deny: [">"] on both publish and subscribe. Nothing passes except what has been explicitly opened. The hub can publish on outbound subjects, listen to heartbeats, respond to incoming requests. The TTS worker can publish its pulse, listen to requests addressed to it, send its responses. Nothing more. This permission is set at the moment the agent is instantiated — not at call time, not on the fly. It is inherited from Claude Code's discipline, which opens rights explicitly at creation and does not revise them in the middle of a run.

What guarantees this rule holds is where the verification is implemented. There is not a copy of this logic in each tool, not a reimplementation per satellite. There is one place — the SDK library, the roxabi-nats whose role we saw in the previous section. One lock code, one place to audit, one place to update the logic if the permission model evolves. Tools trust the library to set the right lock. They do not have to build it themselves.

12

Following a Message

We have spent the previous sections examining locks and keys — who can enter, who cannot, how credentials travel from an environment file to the precise moment a door opens or stays shut. But a workshop is only truly understood by watching the material work. So follow a message, from the first gesture to the reply.

You open Telegram. You write something. You press enter.

At the other end of the line, the factory-telegram adapter is listening. It catches the message — username, conversation identifier, raw text — and reformats it into an event it publishes on the NATS bus. This is not yet a decision: it is a translation. The adapter does not know what the message means; it only knows how to shape it and push it toward the hub.

The hub receives the event. It plays the role we have known from the beginning: it assembles the context, reconstructs the useful slice of history, decides who to route to. Then it publishes a turn request on the subject factory.harness.turn.request — a ticket that says, in substance: someone needs an agent turn; here is everything it needs.

The factory-agent@telegram instance was there, waiting in the queue. It catches the request. This is the harness mould's impression — the same structure, instantiated for this channel, with its own identity. It does not choose to respond; it is the worker the queue designates.

The harness composes the prompt. To do so, it reads the list of authorised tools for this agent, written in its environment file. This is exactly the lock we visited: the list says what this agent has the right to request, and not one tool more. Prompt assembled, the harness calls the model via the llmCLI worker that relays to the actual model.

The model examines the request and decides it needs to generate an image. It requests the image.generate tool.

The request leaves the model and falls into the dispatcher. The dispatcher is uniform — the same room for all tools, the one we saw earlier. It consults the SDK, which knows the path: this request goes via NATS Micro to the imageCLI worker. The message crosses the bus, arrives at the worker, and the image is generated.

Once generated, the image is deposited in the blobstore. And here something quiet happens: what comes back in the response is not the image itself — it is its reference, a blob_ref, a lightweight address that says where to find the thing without carrying the thing. The NATS wire does not carry megabytes; it carries pointers.

The harness receives this response and feeds it back to the model. This is the second turn of the loop. The model now sees that the image exists, that the request was satisfied, and it produces the text response — the sentence the user is waiting for.

The harness emits events toward the hub. The hub broadcasts to the Telegram adapter. The adapter pushes the reply to the user. Telegram displays the message.

A few seconds have elapsed. Every piece has played its note, at its moment, in one continuous flow. The adapter translated, the hub assembled, the harness orchestrated, the dispatcher routed, the worker produced, the blobstore received, the model looped. No piece knew how to do everything — each one knew exactly what it had to do.

Understanding each role separately is what makes the full flow readable from end to end. This is the payoff of all the preceding sections.

13

The Horizon

We are now standing in the light of the threshold. Behind you, the workshop with all its pieces in place, its circuits you can follow with your eyes. In front of you, a few doors still closed — not walls, doors. It is honest to name them.

The first concerns the internal engine of the harness. Everything we have described — the loop, the turns, the tool handling — presupposes an engine that orchestrates these steps. But this engine is not yet chosen. LangGraph is on the table, bringing graph guarantees and resumption. A lightweight custom loop is also considered, simpler and more directly controllable. And Hermes — the Nous Research fork that lives in this ecosystem — could play this role. A prototype will decide. That is the right way to choose: you do not pick an engine on paper, you run it.

The second door is the skills layer — the SKILL.md partitions an agent can read to know when and how to call a tool. This layer will come, likely in the Anthropic format. But it is a next iteration, not the foundation.

The third is the question of sub-agents: a harness calling a harness, an instance delegating part of itself to another. The architecture is ready for it in broad strokes, because a stateless harness can nest without friction. But taking it on in the first version or deferring it to the next iteration — that ridge line remains to be crossed.

There is also a term that floated in a conversation one day: lightpool. Nobody knows exactly what it meant. Probably a confusion with clipool, the Claude process pool we know well. Perhaps an idea still taking shape. That mystery deserves to be cleared up before it becomes a false certainty in exchanges.

And there is the concrete, operational passage: moving from the current shared pool to the at-sign Quadlet instances — those named, isolated units, one per channel. The path is traced, but validating it on a prototype before rolling it out everywhere is the right precaution. You do not flip a production topology on an intuition, however well-founded.

These doors do not obscure what we have seen. They simply indicate where the walk continues.

A little while ago you entered this workshop through the main door — the hub, its NATS subjects, its adapters that translate the outside world. You walked through the tool forge, traced the dispatcher's wires, recognised the harness mould's impression in each instance, understood how locks distribute rights without concentrating them. And you followed a message, from the first gesture on a keyboard to the sentence that comes back in reply. The workshop is coherent. Not perfect, not finished, but coherent — and that is what matters for building on top of it.