@@ -167,7 +167,7 @@ def realign_markdown_tables(*args, **kwargs):
167167
168168# Load .env from ~/.dag/.env first, then project root as dev fallback.
169169# User-managed env files should override stale shell exports on restart.
170- from dag_constants import get_dag_home, display_dag_home
170+ from dag_constants import collar_env, get_dag_home, display_dag_home
171171from dag_cli.browser_connect import (
172172 DEFAULT_BROWSER_CDP_URL,
173173 is_browser_debug_ready,
@@ -322,7 +322,7 @@ def _resolve_prefill_messages_file(config: Dict[str, Any]) -> str:
322322 ``agent.prefill_messages_file`` remains a legacy fallback for older CLI and
323323 godmode-generated configs.
324324 """
325- env_path = os.getenv("COLLAR_PREFILL_MESSAGES_FILE ", "").strip()
325+ env_path = collar_env("PREFILL_MESSAGES_FILE ", "").strip()
326326 if env_path:
327327 return env_path
328328 top_level = str(config.get("prefill_messages_file", "") or "").strip()
@@ -376,7 +376,7 @@ def load_cli_config() -> Dict[str, Any]:
376376
377377 # --ignore-user-config: force-skip the user config.yaml (still honor project
378378 # config as a fallback so defaults stay sensible).
379- ignore_user_config = os.environ.get("COLLAR_IGNORE_USER_CONFIG ") == "1"
379+ ignore_user_config = collar_env("IGNORE_USER_CONFIG ") == "1"
380380
381381 # Use user config if it exists, otherwise project config
382382 if user_config_path.exists() and not ignore_user_config:
@@ -919,10 +919,10 @@ def _prepare_deferred_agent_startup() -> None:
919919 global _deferred_agent_startup_done
920920 if _deferred_agent_startup_done:
921921 return
922- if os.environ.get("COLLAR_DEFER_AGENT_STARTUP ") != "1":
922+ if collar_env("DEFER_AGENT_STARTUP ") != "1":
923923 return
924924 _deferred_agent_startup_done = True
925- _accept_hooks = os.environ.get("COLLAR_ACCEPT_HOOKS ", "").lower() in {
925+ _accept_hooks = collar_env("ACCEPT_HOOKS ", "").lower() in {
926926 "1",
927927 "true",
928928 "yes",
@@ -1811,7 +1811,7 @@ def _detect_light_mode() -> bool:
18111811 _LIGHT_MODE_CACHE = result
18121812 return result
18131813 # 2. Theme hint
1814- theme = (os.environ.get("COLLAR_TUI_THEME ") or "").strip().lower()
1814+ theme = (collar_env("TUI_THEME ") or "").strip().lower()
18151815 if theme == "light":
18161816 result = True
18171817 _LIGHT_MODE_CACHE = result
@@ -1820,7 +1820,7 @@ def _detect_light_mode() -> bool:
18201820 _LIGHT_MODE_CACHE = result
18211821 return result
18221822 # 3. Explicit bg hex
1823- bg_hint = os.environ.get("COLLAR_TUI_BACKGROUND ") or ""
1823+ bg_hint = collar_env("TUI_BACKGROUND ") or ""
18241824 bg_lum = _luminance_from_hex(bg_hint)
18251825 if bg_lum is not None:
18261826 result = bg_lum >= 0.5
@@ -3006,7 +3006,7 @@ def _build_compact_banner() -> str:
30063006 line1 = f"{agent_name} - AI Agent Framework"
30073007 tiny_line = agent_name
30083008
3009- if os.environ.get("COLLAR_FAST_STARTUP_BANNER ") == "1":
3009+ if collar_env("FAST_STARTUP_BANNER ") == "1":
30103010 from dag_cli import __release_date__ as _release_date
30113011 from dag_cli import __version__ as _version
30123012
@@ -3322,7 +3322,7 @@ def __init__(
33223322 _DEFAULT_CONFIG_MODEL = ""
33233323 self.model = model or _config_model or _DEFAULT_CONFIG_MODEL
33243324 # Read max_tokens from config (env var override: COLLAR_MAX_TOKENS)
3325- _env_mt = os.environ.get("COLLAR_MAX_TOKENS ")
3325+ _env_mt = collar_env("MAX_TOKENS ")
33263326 if _env_mt:
33273327 try:
33283328 self.max_tokens = int(_env_mt)
@@ -3358,7 +3358,7 @@ def __init__(
33583358 self.requested_provider = (
33593359 provider
33603360 or CLI_CONFIG["model"].get("provider")
3361- or os.getenv("COLLAR_INFERENCE_PROVIDER ")
3361+ or collar_env("INFERENCE_PROVIDER ")
33623362 or "auto"
33633363 )
33643364 self._provider_source: Optional[str] = None
@@ -3385,9 +3385,9 @@ def __init__(
33853385 self.max_turns = CLI_CONFIG["agent"]["max_turns"]
33863386 elif CLI_CONFIG.get("max_turns"): # Backwards compat: root-level max_turns
33873387 self.max_turns = CLI_CONFIG["max_turns"]
3388- elif os.getenv("COLLAR_MAX_ITERATIONS "):
3388+ elif collar_env("MAX_ITERATIONS "):
33893389 try:
3390- self.max_turns = int(os.getenv("COLLAR_MAX_ITERATIONS ", ""))
3390+ self.max_turns = int(collar_env("MAX_ITERATIONS ", ""))
33913391 except (TypeError, ValueError):
33923392 self.max_turns = 90
33933393 else:
@@ -3419,11 +3419,11 @@ def __init__(
34193419 # by `dag chat --ignore-rules` in dag_cli/main.py. When true we
34203420 # pass skip_context_files=True and skip_memory=True to AIAgent so
34213421 # AGENTS.md/SOUL.md/.cursorrules and persistent memory are not loaded.
3422- self.ignore_rules = ignore_rules or os.environ.get("COLLAR_IGNORE_RULES ") == "1"
3422+ self.ignore_rules = ignore_rules or collar_env("IGNORE_RULES ") == "1"
34233423
34243424 # Ephemeral system prompt: env var takes precedence, then config
34253425 self.system_prompt = (
3426- os.getenv("COLLAR_EPHEMERAL_SYSTEM_PROMPT ", "")
3426+ collar_env("EPHEMERAL_SYSTEM_PROMPT ", "")
34273427 or CLI_CONFIG["agent"].get("system_prompt", "")
34283428 )
34293429 self.personalities = CLI_CONFIG["agent"].get("personalities", {})
@@ -5189,7 +5189,7 @@ def show_banner(self):
51895189
51905190 # Tool discovery is intentionally deferred on the Termux bare prompt
51915191 # path; availability warnings are shown once tools are initialized.
5192- if os.environ.get("COLLAR_DEFER_AGENT_STARTUP ") != "1":
5192+ if collar_env("DEFER_AGENT_STARTUP ") != "1":
51935193 self._show_tool_availability_warnings()
51945194
51955195 # Warn about low context lengths (common with local servers). Keep
@@ -5488,7 +5488,7 @@ def _show_tool_availability_warnings(self):
54885488 def _show_status(self):
54895489 """Show compact startup status line."""
54905490 # Avoid pulling the full tool registry into the bare Termux prompt path.
5491- if os.environ.get("COLLAR_DEFER_AGENT_STARTUP ") == "1":
5491+ if collar_env("DEFER_AGENT_STARTUP ") == "1":
54925492 tool_status = "tools deferred"
54935493 else:
54945494 tools = get_tool_definitions(enabled_toolsets=self.enabled_toolsets, quiet_mode=True)
@@ -6000,7 +6000,7 @@ def new_session(self, silent=False, title=None):
60006000 self.agent._session_db_created = False
60016001 self._session_db.create_session(
60026002 session_id=self.session_id,
6003- source=os.environ.get("COLLAR_SESSION_SOURCE ", "cli"),
6003+ source=collar_env("SESSION_SOURCE ", "cli"),
60046004 model=self.model,
60056005 model_config={
60066006 "max_iterations": self.max_turns,
@@ -11016,7 +11016,7 @@ def run(self):
1101611016 # won't affect the running process — we just want the operator to
1101711017 # see that they're running without the safety net.
1101811018 try:
11019- _redact_raw = os.getenv("COLLAR_REDACT_SECRETS ", "true")
11019+ _redact_raw = collar_env("REDACT_SECRETS ", "true")
1102011020 if _redact_raw.lower() not in {"1", "true", "yes", "on"}:
1102111021 self._console_print(
1102211022 "[bold red]⚠ Secret redaction is DISABLED[/] "
@@ -11154,10 +11154,10 @@ def run(self):
1115411154 self._voice_tts_done = threading.Event() # Signals TTS playback finished
1115511155 self._voice_tts_done.set() # Initially "done" (no TTS pending)
1115611156
11157- if os.environ.get("COLLAR_DEFER_AGENT_STARTUP ") != "1":
11157+ if collar_env("DEFER_AGENT_STARTUP ") != "1":
1115811158 self._install_tool_callbacks()
1115911159
11160- if os.environ.get("COLLAR_DEFER_AGENT_STARTUP ") != "1":
11160+ if collar_env("DEFER_AGENT_STARTUP ") != "1":
1116111161 self._ensure_tirith_security()
1116211162
1116311163 # Key bindings for the input area
@@ -13156,7 +13156,7 @@ def _signal_handler(signum, frame):
1315613156 if getattr(self, "agent", None) and getattr(self, "_agent_running", False):
1315713157 self.agent.interrupt(f"received signal {signum}")
1315813158 try:
13159- _grace = float(os.getenv("COLLAR_SIGTERM_GRACE ", "1.5"))
13159+ _grace = float(collar_env("SIGTERM_GRACE ", "1.5"))
1316013160 except (TypeError, ValueError):
1316113161 _grace = 1.5
1316213162 if _grace > 0:
@@ -13429,7 +13429,7 @@ def _run_kanban_goal_loop_q(cli: "DagCLI", first_response: str) -> None:
1342913429 """
1343013430 import os as _os
1343113431
13432- task_id = (_os.environ.get("COLLAR_KANBAN_TASK ") or "").strip()
13432+ task_id = (_collar_env("KANBAN_TASK ") or "").strip()
1343313433 if not task_id:
1343413434 return
1343513435
@@ -13725,7 +13725,7 @@ def _signal_handler_q(signum, frame):
1372513725 if _agent is not None:
1372613726 _agent.interrupt(f"received signal {signum}")
1372713727 try:
13728- _grace = float(os.getenv("COLLAR_SIGTERM_GRACE ", "1.5"))
13728+ _grace = float(collar_env("SIGTERM_GRACE ", "1.5"))
1372913729 except (TypeError, ValueError):
1373013730 _grace = 1.5
1373113731 if _grace > 0:
@@ -13744,7 +13744,7 @@ def _signal_handler_q(signum, frame):
1374413744 # first so the final debug trace isn't lost; SIGALRM deadman guards
1374513745 # the flush against any rare blocking-I/O case (the reporter measured
1374613746 # flush in <1ms; the alarm is a failsafe, not the common path).
13747- if os.environ.get("COLLAR_KANBAN_TASK "):
13747+ if collar_env("KANBAN_TASK "):
1374813748 try:
1374913749 import signal as _sig_mod
1375013750 if hasattr(_sig_mod, "SIGALRM"):
@@ -13789,7 +13789,7 @@ def _signal_handler_q(signum, frame):
1378913789 # path or URL into a kanban task body never get it routed to the
1379013790 # model's vision input.
1379113791 single_query_image_urls: list[str] = []
13792- _kanban_task_id = os.environ.get("COLLAR_KANBAN_TASK ", "").strip()
13792+ _kanban_task_id = collar_env("KANBAN_TASK ", "").strip()
1379313793 if _kanban_task_id:
1379413794 try:
1379513795 from dag_cli import kanban_db as _kb
@@ -13933,7 +13933,7 @@ def _signal_handler_q(signum, frame):
1393313933 # out (→ sticky block). Gated on the env vars the
1393413934 # dispatcher sets in `_default_spawn`; a no-op for every
1393513935 # normal worker and every non-kanban `-q` run.
13936- if os.environ.get("COLLAR_KANBAN_GOAL_MODE ") == "1":
13936+ if collar_env("KANBAN_GOAL_MODE ") == "1":
1393713937 try:
1393813938 _run_kanban_goal_loop_q(cli, response)
1393913939 except Exception as _goal_exc:
@@ -13957,7 +13957,7 @@ def _signal_handler_q(signum, frame):
1395713957 _exit_code = 0
1395813958 if isinstance(result, dict) and result.get("failed"):
1395913959 _exit_code = 1
13960- if os.environ.get("COLLAR_KANBAN_TASK ") and result.get(
13960+ if collar_env("KANBAN_TASK ") and result.get(
1396113961 "failure_reason"
1396213962 ) in ("rate_limit", "billing"):
1396313963 try:
0 commit comments