Env
env
¶
Assembles container environment variables and volume mounts for agent launches.
Both terok-executor run (standalone) and terok (project orchestrator)
construct identical container environments — shared config mounts, vault
tokens, git identity, unrestricted-mode flags. This module provides
the canonical assembly function so that logic lives in one place.
Usage::
from terok_executor.container.env import ContainerEnvSpec, assemble_container_env
from terok_executor import AgentRoster
result = assemble_container_env(
ContainerEnvSpec(task_id="abc", provider_name="claude", workspace_host_path=ws),
AgentRoster.shared(),
)
# result.env, result.volumes, result.task_dir
CONTAINER_PROTOCOL = 1
module-attribute
¶
Version of the host↔container env/script contract.
Emitted to every container as TEROK_CONTAINER_PROTOCOL. In-container
scripts (terok-env.sh and friends) read it to adapt to the version
the host is shipping. Bumped on breaking changes to the env-var or
script-interface contract between host and container, not on every
release. Old containers on protocol N keep running; new containers get
protocol N+1 and carry the matching host-side code.
ContainerEnvSpec(task_id, provider_name, workspace_host_path, code_repo=None, clone_from=None, branch=None, git_author_name=None, git_author_email=None, git_committer_name=None, git_committer_email=None, authorship='agent', human_name='Nobody', human_email='nobody@localhost', credential_scope='standalone', credential_set='default', vault_transport='direct', vault_required=False, scan_leaked_creds=False, enabled_vault_patch_providers=None, disabled_vault_patch_providers=None, expose_credential_providers=frozenset(), unrestricted=True, timezone=None, agent_config_dir=None, shared_dir=None, shared_mount='/shared', task_dir=None, envs_dir=None, extra_volumes=())
dataclass
¶
Specification for container environment assembly.
All fields use primitives or Path — no terok-specific
types. Callers pre-resolve domain-specific decisions (security class,
authorship mode, SSH mount, gate mirror creation) and pass results here.
task_id
instance-attribute
¶
Unique task identifier.
provider_name
instance-attribute
¶
Agent provider name (e.g. "claude", "codex").
workspace_host_path
instance-attribute
¶
Host-side workspace directory — caller pre-creates, mounted as /workspace:Z.
code_repo = None
class-attribute
instance-attribute
¶
Git URL to clone inside the container (→ CODE_REPO).
clone_from = None
class-attribute
instance-attribute
¶
Secondary clone source for online-mode gate optimization (→ CLONE_FROM).
branch = None
class-attribute
instance-attribute
¶
Git branch to check out (→ GIT_BRANCH).
git_author_name = None
class-attribute
instance-attribute
¶
Resolved from roster provider if None.
git_author_email = None
class-attribute
instance-attribute
¶
git_committer_name = None
class-attribute
instance-attribute
¶
git_committer_email = None
class-attribute
instance-attribute
¶
authorship = 'agent'
class-attribute
instance-attribute
¶
Authorship mode consumed by in-container wrappers (→ TEROK_GIT_AUTHORSHIP).
human_name = 'Nobody'
class-attribute
instance-attribute
¶
Human operator name (→ HUMAN_GIT_NAME). terok resolves from project
config / git config; standalone uses the default or --git-identity-from-host.
human_email = 'nobody@localhost'
class-attribute
instance-attribute
¶
Human operator email (→ HUMAN_GIT_EMAIL).
credential_scope = 'standalone'
class-attribute
instance-attribute
¶
Scope for vault token creation. terok passes project.id.
credential_set = 'default'
class-attribute
instance-attribute
¶
Vault storage namespace to read credentials from. Pairs with
Authenticator.run's
credential_set — if the auth flow stored a token under set
foo, the runtime must read from set foo too or the container
will see empty env. Default "default" matches the shared
host-wide bucket every standalone caller uses; terok overrides for
per-project credentials.
vault_transport = 'direct'
class-attribute
instance-attribute
¶
Vault transport mode: "direct" (HTTP base URL) or "socket"
(Unix socket path via socket_env).
vault_required = False
class-attribute
instance-attribute
¶
When True, raise SystemExit if the vault is
unreachable. When False (default), soft-fail to empty env.
scan_leaked_creds = False
class-attribute
instance-attribute
¶
When True, scan shared mounts for real credential files and emit
warnings. Standalone mode defaults to off; terok enables this.
enabled_vault_patch_providers = None
class-attribute
instance-attribute
¶
Provider subset whose shared config patches should be applied.
None means "all providers with patches". An empty set disables
vault config patching entirely. terok uses this to gate experimental
OAuth routing without affecting standalone executor defaults.
disabled_vault_patch_providers = None
class-attribute
instance-attribute
¶
Provider subset whose previously managed config patch values should
be removed if still owned by terok. None removes nothing.
expose_credential_providers = frozenset()
class-attribute
instance-attribute
¶
Providers whose credential file should remain writable in-container.
By default every provider with a vault.credential_file
gets the file mounted read-only on top of its shared config dir, so an
in-container /login cannot taint the host copy
(terok-ai/terok#873).
Providers in this set keep the writable bind — used by terok's
experimental expose_oauth_token mode where the agent intentionally
manages its own token.
unrestricted = True
class-attribute
instance-attribute
¶
Enable auto-approve flags for all agents.
timezone = None
class-attribute
instance-attribute
¶
IANA timezone name propagated to the container as TZ.
None (the default) means detect the host's timezone via
terok_executor._util.detect_host_timezone — the container
then follows the host. Pass an explicit string ("UTC",
"Europe/Prague") to override, including to pin the container to
UTC for reproducible runs. If neither detection nor an override
yields a zone, TZ is not set and the image default applies.
agent_config_dir = None
class-attribute
instance-attribute
¶
Pre-prepared agent config directory (→ /home/dev/.terok:Z).
shared_dir = None
class-attribute
instance-attribute
¶
Host-side shared directory. Created by the assembly function if set.
shared_mount = '/shared'
class-attribute
instance-attribute
¶
Container-side mount point for the shared directory.
task_dir = None
class-attribute
instance-attribute
¶
Host-side task directory. A temp dir is created if None.
envs_dir = None
class-attribute
instance-attribute
¶
Base directory for shared config mounts. Uses paths.mounts_dir
if None.
extra_volumes = ()
class-attribute
instance-attribute
¶
Additional volume specs from the caller (e.g. SSH mounts from terok).
ContainerEnvResult(env, volumes, task_dir)
dataclass
¶
Assembled container environment ready for RunSpec construction.
Not a RunSpec — omits launch-time concerns (container name, image,
command, GPU, shield bypass). Callers add those and construct RunSpec.
env
instance-attribute
¶
Environment variables for the container.
volumes
instance-attribute
¶
Typed volume specs — the sandbox decides whether to mount or inject.
task_dir
instance-attribute
¶
Host-side task directory. When spec.task_dir was None, this is
an auto-created temporary directory — the caller owns cleanup.
assemble_container_env(spec, roster, *, caller_manages_vault=False, per_container=None)
¶
Assemble container environment variables and volume mounts.
This is the single source of truth for container env/volume assembly.
Both AgentRunner._run() and terok's build_task_env_and_volumes()
delegate here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spec
|
ContainerEnvSpec
|
What the caller wants — all host↔container contract fields. |
required |
roster
|
AgentRoster
|
Agent roster for shared mounts, vault routes, provider identity. |
required |
caller_manages_vault
|
bool
|
When |
False
|
Returns:
| Type | Description |
|---|---|
ContainerEnvResult
|
Assembled env dict, volume tuple, and resolved task_dir. |
Source code in src/terok_executor/container/env.py
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | |