Capability: entities-and-registry
Every pluggable construct is an entity behind one abstract interface per kind, addressed by a registry reference and resolved from one registry.
What it is
The principle the rest of the harness is built on. A prompt, a skill, a tool, a model, a hook, a channel, a renderer, a surface, a store and an agent are all entities; the core loop, plugins and hooks reach them only through the registry, so any of them can be replaced, versioned or served remotely without touching the loop. Lives in tiny_harness/harness/entities/.
Current behaviour
- The system SHALL define one abstract interface per entity kind:
prompt,skill,tool,llm,system_one,hook,channel,renderer,surface,store,agentandcommand. The agent interface issend_message(an async stream of the A2A SDK's ownMessage,Taskand update events) andcancel_task, with an agent card. - The system SHALL address every entity instance by an
EntityRefof(kind, id, version), whereversionisNonefor kinds that are not versioned. A version specifier is resolved as sherma resolves it: a PEP 440 specifier selects among the concrete registered versions,*means the latest concrete one, and an entry registered under*is the fallback when no concrete version matches. - WHEN an entity is resolved THEN the registry SHALL return exactly one instance or raise the typed not-found error; it SHALL NOT fall back to a default.
- The registry SHALL hold local entries (an instance or a factory) and remote entries (a URL and the application protocol it speaks: A2A for agents, MCP for tools and prompts, HTTPS for models and remote hooks); a remote entry with no protocol SHALL be refused.
- WHEN two registrations carry the same
(id, version)THEN the second SHALL be refused unless the caller asks for an override. - A
Commandentity SHALL wrap aCommandSpec(name matching[a-z][a-z0-9-]*, description, argument hint) underEntityRef(kind="command", id=<name>), unversioned. TheCommandRegistry(harness/commands/registry.py) takes registrations from code (register(spec, handler)orregister_executor(spec, executor), each withoverride=), from plugins and from the built-ins; an invalid or duplicate name raisesCommandErrorwhen the harness is built. It is frozen before the worker starts and published into the entity registry, and its specs are what the card's commands extension lists. - The registry SHALL be one object with a typed
get, exposed to hooks and plugins, so a plugin can register, override or remove an entry. Divergences from sherma'sRegistry[T]: one registry instead of a subclass per kind, a remote entry carries its protocol, notenant_id.
Design
design.md § Entities and registry, design.md § sherma: reused and replaced.
History
| Work item | What changed | Links |
|---|---|---|
| issue-3 | Entity base, kinds, references, remote locations and the registry (Layer 1); the surface kind added with the renderers (Layer 7) | spec, PR #7, PR #13 |
| issue-25 | The command kind and the Command entity, filled by CommandRegistry and published before the worker starts | spec, PR #26, decision-007 |