Components and plugins¶
A component is any pluggable part of tau: a tool, a subcommand, a model provider, a session backend, a context source or a hub service. Components reach tau through a built-in seed, an entry point in a tau.* group declared by any installed distribution, or an in-process registration. tau.toml decides which discovered components are on, and tau components shows all of them. The rule that makes this safe: a component that fails to load is logged with its distribution name and skipped; it never breaks the CLI, and a tool that reaches the agent behind the catalog's back is refused. The decision is ADR 0005.
A plugin is a third-party distribution that provides components. To write one, see Write a plugin.
The six entry-point groups¶
| Group | Entry point value | Picked by |
|---|---|---|
tau.tools |
an AgentTool with a tier (@tau_tool), a list of them, or a zero-argument factory |
build_agent, all of them minus [components.tools] disabled |
tau.commands |
a click.Command, mounted as tau <name> |
the tau command |
tau.providers |
factory(RoleConfig, env) -> Model; optional required_env = [["VAR", …], …] on the factory (credential alternatives) |
a role's provider in tau.toml |
tau.sessions |
factory(Config) -> SessionStore |
[sessions] backend |
tau.context |
factory(Config) -> ContextSource (a callable returning {"nodes": …, "budget": …}) |
build_agent when no explicit context_sources are passed, minus what [components] context leaves out |
tau.hub_services |
factory(Config) -> HubService |
tau hub run, after the control API, minus what [components.hub] services leaves out |
tau.channels is reserved for hub-hosted channels; a channel that runs inside the hub ships a tau.hub_services entry point today.
Precedence¶
- A seed name (
bedrock,anthropic,fake,memory,file) wins over an entry point of the same name; the entry point is logged and ignored, so an installed package cannot silently replacebedrock. - An in-process registration (
register_provider,register_session_backend) replaces anything, because it is explicit code. Config.loadvalidates provider and backend names without loading any entry point, sotau versionandtau hub statusnever import a provider SDK. A name that is declared but fails to load errors when the role is resolved, with the entry point's own error:Model provider 'x' from <distribution> failed to load: …. Only a name no distribution declares is anUnknown model provider.
[components] in tau.toml¶
[components]
context = [] # enabled tau.context sources; empty = every discovered one
[components.tools]
disabled = ["demo_physical_action", "dist:tau-example-tool"] # tool names or dist:<distribution>
[components.hub]
services = [] # enabled tau.hub_services; empty = every discovered one
[component.telegram] # a component's own settings: Config.component("telegram")
chat_id_env = "TELEGRAM_CHAT_ID"
tools.disabledcan only remove tools. It never adds one, gives one a tier or changes a tier. An explicitbuild_agent(tools=[...])bypasses it.- Unknown keys inside
[components],[components.tools]and[components.hub]are aConfigError, so a typo such asdisablecannot leave a tool switched on. - A name nothing installed provides is a
tau doctorwarning. - Nothing in
[components]can replace the tier gate, the approver or the catalog.
tau components¶
In a repository checkout with the dev group installed, the listing also shows the three test-fixture distributions (tau-example-*); a plain install shows only tau-core and tau-tui:
tau.tools
example_echo tau-example-tool 0.0.1 enabled tier 0
current_time tau-core 0.2.0 enabled tier 0
demo_physical_action tau-core 0.2.0 enabled tier 2
tau.commands
tui tau-tui 0.2.0 enabled tau tui
chat tau-core 0.2.0 enabled tau chat
components tau-core 0.2.0 enabled tau components
doctor tau-core 0.2.0 enabled tau doctor
hub tau-core 0.2.0 enabled tau hub
init tau-core 0.2.0 enabled tau init
tau.providers
bedrock tau-core 0.2.0 enabled in use: brain, fast (built-in)
anthropic tau-core 0.2.0 enabled in use: brain, fast (built-in)
fake tau-core 0.2.0 enabled available (built-in)
fake2 tau-example-provider 0.0.1 enabled available
ollama - - disabled not available until issue 012; used by local (planned)
tau.sessions
memory tau-core 0.2.0 enabled available (built-in)
file tau-core 0.2.0 enabled in use (built-in)
example tau-example-provider 0.0.1 enabled available
tau.context
example tau-example-service 0.0.1 enabled
tau.hub_services
example tau-example-service 0.0.1 enabled
Columns: name, distribution and version, enabled/disabled (from [components]), then a note: tier N for a tool (or no tier: never registered), tau <name> for a command, in use: <roles> / available / planned for a provider, in use / available for a backend, and the load error for anything that failed. --json gives the same rows as objects with group, name, distribution, version, source (built-in, entry point, registered, planned), enabled, note, error.
Fail-closed rules¶
These are the invariants every component runs under. They are what makes an untrusted plugin safe to install.
- A tool without a tier is never registered.
@tau_tool(tier=…)records the tier in the tool spec; a plain Strands@toolraisesUntieredToolErrorin the catalog, is refused bybuild_agent(tools=[…])and is skipped with a warning when a plugin ships it. - An unknown tool is refused, not run. Every call is looked up live in the
ToolCatalog; a tool that reached the Strands agent through aPluginor another side door is refused withTool '<name>' is not registered; it was not run.and anerrorevent. - The tier gate has the last word.
TierHookis registered atHookOrder.SDK_LAST;build_agentraises aConfigErrorfor any hook registered above it, so no plugin hook can rewrite a call after it was approved. A hook added to the SDK agent after build cannot be refused; the gate then records a refused call that ran, or an approved call whose arguments changed, as anerrorwithwhere: tier_gate. - Nothing approves on its own. No component can replace the approver; a channel passes its own
Approvertobuild_agent, and the default rejects. - A broken component is skipped, never fatal. An entry point that fails to import or returns the wrong kind of object is logged with its distribution and left out;
tau componentsandtau doctorshow the error. - A hub service is optional. One that fails to build or start is logged and skipped; the hub runs on. Control API routes are additive only:
add_routeraises for a(method, path)that exists, so no service can replaceGET /health,GET /statusor another service's route. - Tiers come from the process, not from the wire. The
annotations["tau"]block in a tool spec is authoritative only for tools registered in-process. A spec that arrives from outside (an MCP tool provider, layer 5) has it stripped and gets its tier from the hub's own configuration. tools.disabledonly removes. It cannot add, promote or demote a tool.
In code¶
from tau_core import register_provider, register_session_backend
from tau_core.i18n import register_messages
register_provider("mine", make_model, required_env=[["MINE_API_KEY"]])
register_session_backend("mine", make_store)
register_messages({"mine.hello": {"en": "Hello", "tr": "Merhaba"}})
Both registrations replace a seed or an entry point of the same name and invalidate the cached merged view. Config.component("<name>") returns a fresh dict of the component's [component.<name>] table.