Roster
roster
¶
Loads agent and tool definitions from layered YAML config into a queryable roster.
Delegates to .loader for YAML deserialization and roster construction,
and to .config_stack for generic layered config resolution.
__all__ = ['AgentRoster', 'EgressProjection', 'providers_config_dir']
module-attribute
¶
AgentRoster(_agents=dict(), _providers=dict(), _auth_providers=dict(), _vault_routes=dict(), _sidecar_specs=dict(), _installs=dict(), _helps=dict(), _mounts=(), _agent_names=(), _all_names=(), _web_ingress=frozenset())
dataclass
¶
Queryable view over the loaded set of agents and tools.
Returned by load_roster;
grouped accessors expose agents, auth providers, vault routes,
sidecar specs, install snippets, and help blurbs by name.
agents
property
¶
All headless agents (kind: agent only).
providers
property
¶
All vault-routed providers (LLM endpoints + tool APIs), keyed by clean name.
The endpoint axis: where requests go and how the real credential is
attached. Loaded from resources/providers/*.yaml. The
routes.json the sandbox vault reads is generated from these.
auth_providers
property
¶
All auth providers (agents + tools with auth: section).
vault_routes
property
¶
All vault routes, keyed by provider name.
sidecar_specs
property
¶
All sidecar tool specs, keyed by tool name.
agent_names
property
¶
Names of kind: agent entries (for CLI completion).
all_names
property
¶
Return the names of agents, tools, and selectable LLM providers.
installs
property
¶
All install specs, keyed by roster name (entries without one are absent).
helps
property
¶
All help blurbs, keyed by roster name (entries without one are absent).
web_ingress
property
¶
Names of entries that publish a host HTTP port (web_ingress: true).
Consumers (e.g. terok's task launcher) use this to decide whether to allocate a published port and drop a per-task auth token into the container-visible config dir.
mounts
property
¶
All shared directory mounts (auth dirs + explicit mounts: sections).
Deduplicated by host_dir — if auth and mounts define the same
directory, only one entry is returned.
resolve_selection(selection)
¶
Resolve a user-supplied selection into the full set of roster names to install.
Accepts the literal string "all" (every roster entry that has an
InstallSpec) or a tuple of
selection tokens. Each token is either a roster name (include) or a
name prefixed with - (exclude). The pseudo-name "all" is also
valid as an include token, meaning "seed from every installable
entry"; this combines naturally with excludes, e.g. ("all",
"-vibe") installs everything except vibe. When no include tokens
are present (only excludes), the seed is the full roster.
Includes are expanded transitively via depends_on before
excludes are applied, so an exclude that names a dependency of a
kept agent will silently drop that dependency — likely producing a
broken image, but matching the user's literal request.
Returns the names sorted alphabetically — the canonical order used for the OCI label, the tag suffix, and the in-container manifest.
This method raises ValueError if an include or exclude specifies a
provider-only name or an unknown name. It raises TypeError if
selection is a string other than "all". This check prevents
iteration through the characters of a bare name such as "claude".
An exclusion has no effect if the agent is not in the resolved include
set.
Source code in src/terok_executor/roster/loader.py
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | |
get_agent(name, *, default_agent=None)
¶
Resolve an agent name to an Agent.
Falls back to default_agent, then "claude".
Raises SystemExit if the resolved name is unknown.
Source code in src/terok_executor/roster/loader.py
get_auth_provider(name)
¶
Look up an auth provider by name.
Raises SystemExit if the name is unknown.
Source code in src/terok_executor/roster/loader.py
get_sidecar_spec(name)
¶
Look up a sidecar spec by tool name.
Raises SystemExit if the name has no sidecar configuration.
Source code in src/terok_executor/roster/loader.py
generate_routes_json()
¶
Generate the routes.json content for the sandbox vault server.
Emits one entry per provider — keyed by its clean name — so the vault can route to any authenticated provider, not just the one some agent binds by default. This is what lets a harness (opencode, pi) reach a provider no agent owns, and what keeps a provider routable after its shim agent is collapsed away. Empty/absent optional fields are stripped.
Source code in src/terok_executor/roster/loader.py
deny_to_vault_hosts(*, exposed_credential_providers=frozenset())
¶
Hosts to deny directly at the egress firewall (shield security_deny, t20).
Every provider the vault relays contributes its
relayed_hosts
(upstream + path overrides + OAuth-refresh endpoint) — the agent must
reach those only through the loopback vault. Two classes are skipped:
shared_domainproviders (gitlab.com,sonarcloud.io): the API rides an apex that also servesgit push/ docs, so a host-level deny would kill legitimate traffic; credential containment carries the weight instead.- the providers bound by
exposed_credential_providers— roster-entry (agent/tool) names in terok's experimentalexpose_oauth_tokenmode, where the agent holds its real credential in-container (vault bypassed) and so must reach the endpoint directly. Each entry is mapped to the provider it binds (provider_binding.default).
A pure function of the roster and exposed_credential_providers, mirroring
generate_routes_json:
the vault routes every provider, so every relayed host is denied.
Source code in src/terok_executor/roster/loader.py
compose_egress(*, exposed_credential_providers=frozenset())
¶
Project the roster into the shield's egress tiers.
Bundles the deny_to_vault_hosts
set (t20) with the union of every provider's
egress_allow
(t30) into one EgressProjection;
both tuples are sorted and de-duplicated for a deterministic bundle.
exposed_credential_providers — roster-entry (agent/tool) names whose real
credential is exposed in-container; the providers they bind are left
reachable (see
deny_to_vault_hosts).
Source code in src/terok_executor/roster/loader.py
collect_all_auto_approve_env()
¶
Merge auto_approve.env from all agents into one dict.
Source code in src/terok_executor/roster/loader.py
collect_opencode_provider_env()
¶
Collect the TEROK_OC_{NAME}_* env vars for all OpenCode-driven providers.
Source code in src/terok_executor/roster/loader.py
load()
staticmethod
¶
Load a fresh roster from the current configuration.
This method reads the configuration on each call. It does not replace
the process-wide snapshot from
AgentRoster.shared.
Source code in src/terok_executor/roster/loader.py
shared()
staticmethod
¶
Return the process-wide cached roster.
Loaded on first access; every subsequent call returns the same
instance. Use this from anywhere that just needs the global
view. Call
AgentRoster.load
when the caller needs the current configuration.
Source code in src/terok_executor/roster/loader.py
parse_selection(raw)
staticmethod
¶
Normalise a user-supplied agent selection string.
Accepts a comma-list of selection tokens or the literal "all".
Each token is either an agent name ("claude") or a name
prefixed with - to exclude it from the selection
("-vibe"). The pseudo-name "all" is also valid as a
token, so "all,-vibe" means "everything except vibe". When
the input contains only excludes ("-vibe"), the selection
seeds from every installable entry — same effect as
"all,-vibe".
Whitespace is stripped, empty / whitespace-only entries dropped,
and case folded. Empty or all-whitespace input collapses to
"all" — the same shape
AgentRoster.resolve_selection
expects. Unknown names are not checked here;
resolve_selection does that.
Source code in src/terok_executor/roster/loader.py
validate_selection(raw)
¶
Reject raw with SystemExit(2) if it names roster entries we don't have.
CLI-flavoured: prints a Invalid agent selection: … line on
stderr and exits. Domain callers that just want the parsed
tuple should use
parse_selection
+ resolve_selection
and handle ValueError themselves.
Source code in src/terok_executor/roster/loader.py
prompt_selection()
¶
Print the installed roster and read one line of executor grammar.
Empty input → "all". Non-interactive stdin (closed pipe)
exits with a hint to pass the selection positionally instead.
Source code in src/terok_executor/roster/loader.py
ensure_vault_routes(cfg=None)
¶
Generate routes.json from this roster and write it to disk.
The routes file is written to the path configured in
SandboxConfig (typically
~/.local/share/terok/vault/routes.json).
When cfg is None, falls back to standalone defaults.
Returns the path to the written file.
Source code in src/terok_executor/roster/loader.py
doctor_checks(*, token_broker_port=None)
¶
Return agent-level health checks for in-container diagnostics.
Delegates to
terok_executor.doctor for the actual
check factories; this method is the canonical entry point so
consumers can discover the checks through the roster.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token_broker_port
|
int | None
|
Host-side vault broker TCP port. |
None
|
Source code in src/terok_executor/roster/loader.py
EgressProjection(deny_to_vault=(), provider_allow=())
dataclass
¶
Roster-derived egress policy for a task's shield bundle.
Produced by AgentRoster.compose_egress
and handed (via the sandbox) to the shield's tier writer: deny_to_vault
seeds the security_deny tier (t20), provider_allow the
provider_allow tier (t30). Both tuples are sorted and de-duplicated so
the projection is deterministic across runs.
deny_to_vault = ()
class-attribute
instance-attribute
¶
Relayed provider endpoints the agent may reach only through the vault, denied directly at the egress firewall (shared-domain and exposed-credential providers excluded).
provider_allow = ()
class-attribute
instance-attribute
¶
Extra runtime-egress hosts the providers legitimately need
(egress.allow in the roster), allowed at the egress firewall.
providers_config_dir()
¶
Return the current directory for user provider files.
The function uses the shared XDG-aware Terok configuration root. The
default directory is ~/.config/terok/providers/. Terok also reads the
legacy ~/.config/terok/agent/providers/ directory. Do not use the
legacy directory for new files.
Source code in src/terok_executor/roster/loader.py
__getattr__(name)
¶
Resolve a re-exported name to .loader on first access (PEP 562).