direnv #
a workspace's .envrc reaches the model's run() jobs the way direnv loads
it into the person's shell, and direnv's own allow list decides: a file they
allowed loads, a blocked or denied one does not. albedo keeps no state of its
own about it.
in the kernel #
priv/python/albedo_direnv.py runs before each run() (run.py) and
brings os.environ up to date with direnv export json, as direnv's shell
hook does before each prompt. the kernel is the shell: its folder is
os.getcwd(), so os.chdir into another project loads that one's .envrc,
and leaving it unloads it. jobs inherit os.environ, so everything the kernel
starts afterwards (pipes, files searches) sees the same environment. it runs
wherever the kernel does, remote hosts included.
- direnv is looked up once per kernel on its PATH; without it nothing runs.
- with no
.envrcin the folder or above it, and nothing this kernel loaded to take back, it costs a fewstats. an environment the daemon inherited from the shell that started it is left alone. - an unchanged file answers nothing in a few milliseconds; an edited one (or
a file it watches) reloads by itself. a first evaluation (
use flakebuilding a dev shell) may take up to 600 s and holds thatrun(). - what direnv says (
direnv: loading …,direnv: export +FOO ~PATH,direnv: unloading) prints into the cell, so the model sees why its environment changed. direnv's blocked message is reworded so it does not tell the model to rundirenv allow: allowing is the person's call. If a previously loaded file changes and is blocked, the kernel unloads the old environment before starting the job without it; a blocked reload never keeps stale values from the old file. direnv watches file mtimes at one-second resolution, so an.envrcrewritten within the same second as its last load is not noticed until it changes again. - it never raises: a failure starts the job without the environment.
in the tui #
when a chat opens, and after /cd, the tui runs direnv status --json in
the workspace (chat_direnv.go), only when the daemon and the workspace are
both on this machine: direnv allow is the person's own act there. for a
file direnv blocks (new, or changed since it was allowed) it shows a question
above the composer. while the composer is empty the question owns the letter
keys: y runs direnv allow <file> and the next run() loads it, n (or
esc) puts it away until the chat opens again, as direnv repeats its blocked
message at the next cd. every other letter is held back, so the first letter
of a prompt typed without reading never answers it; a draft already in the
composer keeps typing normally. denied files never ask.