Agents in the Open Part 3: How the Coordinator Picks a Specialist

Orrery's coordinator doesn't answer questions itself. It hands each one to a specialist: Kafka, Kubernetes, observability, the ops journal, and any others installed. This part is about how that...

Orrery's coordinator doesn't answer questions itself. It hands each one to a specialist: Kafka, Kubernetes, observability, the ops journal, and any others installed. This part is about how that choice is made, and why the old way kept producing the same kind of bug once the platform was open to specialists I didn't write (Part 17 of the previous series).


The Bug That Kept Coming Back

Specialists were already plugins, registered through Python entry points. But the coordinator still kept a table of facts about the built-in ones:

Every one of those facts could outlive the specialist it described. In the lab, with Kubernetes, Docker and Elasticsearch switched off, they did:

Fixing these one by one wasn't enough, because each one came from the same design. A third-party specialist also suffered from it the other way round: it could be routed to, but it could never join a sweep or offer a fix.


The Decision: A Specialist Declares What It Contributes

As of Orrery 0.6.6 (ADR-005), an entry point names a SpecialistSpec: the agent, plus what it adds to the rest of the platform. Each contribution carries the tools that implement it.

specialist = SpecialistSpec(
    agent=root_agent,
    routing_hint="Kubernetes cluster info, nodes, pods, deployments, ...",
    health_check=HealthCheck(
        system="Kubernetes",
        checks="...", criteria="...",
        tools=(get_cluster_info, get_nodes, get_events, list_pods),
    ),
    remediation=Remediation(
        actions=(restart_deployment, scale_deployment, rollback_deployment),
        playbook="...",
        verify=(get_deployment_status, list_pods, describe_pod),
    ),
)

The coordinator now imports no specialist. Its routing section, the chat sweep, the batch workflow's checkers, the remediation loop and the journal step are all built from the declarations of the enabled specialists. The coordinator can't mention a specialist that is switched off, because nothing about that specialist is in its inputs.

Before: the coordinator kept tables about specialists. After: each specialist declares a routing hint, health check, remediation and journal, and the coordinator is built from the enabled ones

Two design choices matter more than the shape:


Three Layers, Each One Narrows the Last

Which specialists exist is decided before any question, in three layers:

Three narrowing layers: installed packages, then what the operator allows in the environment, then what an admin enables in the console; the coordinator is built from the result

The coordinator tree is rebuilt for every catalog change and swapped in atomically. A turn already running finishes on the tree it started with.


Then the Model Picks

The per-turn choice is still the model's: each enabled specialist is an AgentTool, and the routing section gives one line per specialist. That step is probabilistic by design. Three things bound it:

What isn't covered yet: there is no routing eval. make eval scores each specialist on its own questions, not the coordinator's choice between them. Now that third parties write routing hints, an eval generated from the enabled set, including a case where a hint tries to inject instructions, is the next check to add. The ADR lists this and its other limits openly. An independent review of the first version found that it claimed more than the code did, so the record now says what is not guaranteed.


The Pattern

When a central component keeps facts about plugins, those facts outlive the plugins. Move each fact into the plugin, with the code that makes it true, and build the central component from the enabled plugins' declarations. The same idea runs through Python entry points, pytest plugins and A2A Agent Cards. What made it safe here was checking each declaration when the specialist loads.

That leaves one question: what happens when the specialist wasn't written by me? That's Part 4.

Read on Tirraflow