ROADMAP & CHOICES
The Roxabi Factory
An agent engine extended with a jobs layer — the choices that shape it, and the order we build them in.
An Engine, Extended
The Factory is not a new system. It is the agent engine that already runs the Roxabi bots — a hexagonal core (ports & adapters), a hub-and-spoke topology, a registry of agents, and a pool of workers dispatched over a message bus — extended with one new layer: jobs. That layer turns activity into content, posts it, and runs the loop around it.
The consequence is liberating. The core left to build is smaller than the first brain-dump suggested: the worker pool, the bus, the typed contracts, the scheduler — all already run in production. The rule of scope follows directly — every new capability is an adapter on the hexagon, never a new core.
The engine already exists. The Factory is a jobs layer on top of it — an extension, not a rewrite.
Value Before Framework
The naive plan builds the framework first: a generic core, then modules, then publishing, then routines. That is the classic trap — a general machine standing in front of its first unit of value. We invert it.
First a thin vertical slice, human-gated end to end: one signal of what was done → the worker generates one post → a human approves → it publishes. It reuses the bus and the worker pool; the harness is minimal; there is no framework yet. Then we measure reach. Only then do we generalise the harness and the watcher — and only over the pieces the slice proved necessary.
Human-in-the-loop is the default until reach — and reputation risk across two brands — is measured. A gate, not an afterthought.
A Worker Is Not a Tool
The single most clarifying decision in the design. The words « tool » and « worker » had drifted across four parallel design spaces; this is the line that resolves them.
Two roles, kept apart. A provider is the service that backs a tool — and when it is a self-hosted process we run on the bus with a heartbeat, it is a satellite. One provider exposes many tools: the image satellite exposes image.generate, image.list_engines, image.cancel. A worker is the other end — a compute instance that consumes tools to run a job. A worker is not a tool, and not a provider; it is what does the work.
And a worker does not improvise. It runs a workerEngine — a coded pipeline, a deterministic sequence — that calls three kinds of step: the harness (one pure agentic turn, where the model decides and its in-turn tools fire, with no workflow logic of its own), the tools, and plain internal code. The harness is a callee of the engine, not a flavour of it — agency where you want a decision, code where you want a guarantee.
- Provider — the service that backs a tool. Transport-agnostic; one provider, many tools.
- Satellite — a provider deployed as a self-hosted process on the bus, with a heartbeat. Every satellite is a provider; not every provider is a satellite.
- Worker — a compute instance that consumes tools to run a job. Not a tool, not a provider.
- workerEngine — the coded pipeline a worker runs; orchestrates harness, tools, and internal code.
- Harness — one pure agentic turn; the model decides. A step the engine calls, never the pipeline itself.
To the model's reasoning loop, a remote image.generate and a built-in bash look identical — same shape, same result type. The transport difference is invisible.
Five Layers of Tool
Not every tool is atomic. The model has five layers, from a single primitive call up to a recursive sub-agent — and one pipeline dispatches them all.
- L0a — Built-in. Compiled into the engine; in-process; always available.
bash, file read/write, web fetch. - L0b — Remote. A capability satellite on the bus, discovered by heartbeat.
image.generate,voice.tts. - L1 — Macro. A deterministic chain of primitives, with no second model in the loop.
- L2 — Skill. An instruction-layer composite — a document that guides the model through a domain sequence.
- L3 — Sub-agent. A nested, isolated agent call that returns a summary upward.
The decisive choice is a uniform dispatcher: one access-control gate, one result type, the transport varying underneath. Not a branched pipeline where built-ins and remote tools each grow their own rules — the discipline of one path is what keeps the engine readable in an afternoon.
Domains by Nature
The typed contracts that travel the bus had been listed flat, mixing two natures in one drawer. We separate them.
A domain is tool-nature when its only reason to exist is to expose a capability the model invokes — voice, image, and the capability satellites to come. Everything else is plumbing: the engine's own inference transport, the job bus, persistence, security, observability, delivery.
The sharp edge is a single rule:
tool-surface ≠ tool-nature
github plumbing exposes a built-in tool → stays plumbing
inference substrate exposes a generate call → stays plumbingA plumbing domain may incidentally expose a tool without becoming tool-nature. Surfacing a tool does not promote the wire domain. That rule is what keeps the separation honest instead of letting everything drift into « tool ».
A second rule draws the line inside « provider » — because not every provider runs on the bus:
provider ⊋ satellite
self-hosted process on the bus → satellite (heartbeats — voice, image, our Postiz adapter)
a cloud API / one-shot CLI we call → provider (no heartbeat — X, GitHub, a bash tool)A provider is a satellite only when it is something we run on the bus that heartbeats; a cloud API we merely call, or a one-shot command-line tool, is a provider without a satellite's footprint. And one trap to avoid: a self-hosted backing service — a whole app like our Postiz fork (web, database, Redis) — is infrastructure, like Postgres. A running container is not a heartbeat; the heartbeat comes from our adapter in front of it. Backing service, provider, tool: three layers, never collapsed into one.
The payoff is an addressable plane. Tool-nature subjects carry a tool. marker — …tool.voice.tts… — so the consumer side subscribes to the entire tool plane at once, and discovers what is available through one registry.
Isolation is the point. Once « the tools » are a plane, the harness and the workers address and discover them as one.
The Roadmap
Where this goes, in order — substrate first, value next, framework last.
- Substrate — in production: the bus, the typed contracts, the worker pool, the scheduler.
- Thin slice — one signal → one post → approve → publish; measure reach. The keystone.
- Generalise — the harness and the job-watcher, over what the slice proved necessary.
- Tools — the shared registry, the tool SDK, the satellites migrated onto the five-layer model.
- Harness & workers — the pure agentic harness and a fleet of workers running workerEngines, both consuming the tool plane.
The design is settled; the build is sequenced, not rushed. Primitives, not a framework.