The CLI loads .env itself — init's promise finally holds

First finding of Eric's clean-room run, and the exact kind the
rehearsal exists for: init writes credentials to .env, but nothing
ever loaded it — the dev repo's committed .envrc + direnv did it
invisibly, and a fresh directory has neither. The web banner then
advised "run bggpipe init or load .env", circular counsel for someone
who just ran init.

A typer callback now loads ./.env before every command, using the
same parsing rules as the wizard that writes it (export prefixes,
quoted values, quoted-empty = unset). Real environment variables
always outrank the file, so direnv setups and explicit overrides keep
working unchanged. Verified in a scrubbed-environment clean room: the
credentials banner is gone with nothing but .env present.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
Eric Wagoner
2026-08-06 09:50:49 -04:00
co-authored by Claude Fable 5
parent 2542560d57
commit 1df784e253
4 changed files with 65 additions and 1 deletions
+28
View File
@@ -190,3 +190,31 @@ def test_fresh_config_template_carries_both_vision_blocks(tmp_path, monkeypatch)
cfg = load_config(tmp_path / "config.toml")
assert cfg.vision_provider == "anthropic"
assert cfg.model == "claude-sonnet-5" # active block applied cleanly
def test_load_env_file_exports_without_overriding(tmp_path, monkeypatch):
"""A fresh directory must work straight after init: the CLI loads .env
itself. A real environment variable always outranks the file."""
from bggpipe.init_wizard import load_env_file
env = tmp_path / ".env"
env.write_text(
"# comment\n"
'export BGG_USERNAME="someone"\n'
"BGG_API_TOKEN=tok-123\n"
"EMPTY=''\n"
"BGG_PASSWORD=from-file\n"
)
monkeypatch.delenv("BGG_USERNAME", raising=False)
monkeypatch.delenv("BGG_API_TOKEN", raising=False)
monkeypatch.delenv("EMPTY", raising=False)
monkeypatch.setenv("BGG_PASSWORD", "from-environment")
loaded = load_env_file(env)
assert set(loaded) == {"BGG_USERNAME", "BGG_API_TOKEN"}
assert os.environ["BGG_USERNAME"] == "someone"
assert os.environ["BGG_API_TOKEN"] == "tok-123"
assert "EMPTY" not in os.environ # quoted-empty means NOT set
assert os.environ["BGG_PASSWORD"] == "from-environment" # env wins
assert load_env_file(tmp_path / "absent.env") == []