Documentation
¶
Overview ¶
Package shellenv reads the environment a user's login shell sets up, so a background process started from a desktop launcher (with a bare PATH) or from a coding agent (with the agent's environment) sees the same tools and settings as the user's terminal.
The shell runs as an interactive login shell in its own session, without a terminal, with a timeout. It is given only the session's own variables (see Session) and a default PATH, so its output depends on the user's startup files rather than on whoever started baum. If it prints nothing, a login shell that is not interactive is asked instead. A program printed between two random markers reports the resulting environment as JSON, so whatever the startup files print is ignored. Values are never logged.
Windows has no login shell. There the result is the inherited environment with the PATH a new logon would get: the system Path followed by the user's, from the registry. A tool installed after the starting process was (winget, an installer that edits the user Path) is found without signing out, and so is one only the user's Path names when an agent started baum.
Index ¶
Constants ¶
const DefaultAgentRetry = time.Minute
DefaultAgentRetry is how long Agent waits after a failed login shell run before asking again.
const DefaultTimeout = 10 * time.Second
DefaultTimeout bounds one resolution; slow startup files fall back to the inherited environment.
const ResolvingVariable = "BAUM_RESOLVING_ENVIRONMENT"
ResolvingVariable is set to 1 in the shell's environment, so startup files can skip slow or interactive work while baum reads the environment.
Variables ¶
var ErrUnsupported = errors.New("login shell environment is not supported on this platform")
ErrUnsupported is returned where there is neither a login shell nor a registry to ask.
var Kept = []string{
"USER", "LOGNAME", "SHELL", "LANG", "TZ",
"SSH_AUTH_SOCK", "DBUS_SESSION_BUS_ADDRESS", "DISPLAY", "WAYLAND_DISPLAY",
"GIT_SSH_COMMAND", "GIT_SSH",
"PATH",
"HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY", "ALL_PROXY", "http_proxy", "https_proxy", "no_proxy", "all_proxy",
"SSL_CERT_FILE", "SSL_CERT_DIR", "NODE_EXTRA_CA_CERTS",
"GITHUB_TOKEN", "GH_TOKEN", "GH_ENTERPRISE_TOKEN", "GITHUB_ENTERPRISE_TOKEN", "GH_HOST", "GH_CONFIG_DIR", "GH_PATH",
"ANTHROPIC_API_KEY", "CLAUDE_CONFIG_DIR", "CODEX_HOME",
}
Kept lists the variables a background baum process keeps, besides BAUM_* and LC_*: the session, the tools' PATH, network settings, GitHub tokens and the backend CLIs' configuration directories. Nothing else is passed on.
var Locations = []string{
"HOME", "XDG_CONFIG_HOME", "XDG_DATA_HOME", "XDG_STATE_HOME", "XDG_CACHE_HOME", "XDG_RUNTIME_DIR",
"TMPDIR", "USERPROFILE", "APPDATA", "LOCALAPPDATA",
}
Locations decide where baum keeps its files: the daemon's lock, socket and job journal, the registry, caches and stores. They always come from the starting process, never from the login shell, because the daemon resolved its lock and socket from them before reading the shell; a location only the shell sets would put its job journal somewhere another daemon could also use.
var Session = []string{
"HOME", "USER", "LOGNAME", "SHELL", "TMPDIR", "LANG", "TZ",
"XDG_CONFIG_HOME", "XDG_DATA_HOME", "XDG_STATE_HOME", "XDG_CACHE_HOME", "XDG_RUNTIME_DIR",
"SSH_AUTH_SOCK", "DBUS_SESSION_BUS_ADDRESS", "DISPLAY", "WAYLAND_DISPLAY",
}
Session lists the inherited variables the shell is given: where the user's files are and how to reach the desktop session's agents. Everything else comes from the shell's startup files.
Functions ¶
func Arguments ¶
Arguments are the flags that make shell an interactive login shell running one command, which the caller appends.
func Merge ¶
Merge builds a background process's environment. The Locations only ever come from inherited, and stay unset when it lacks them. With a resolved login shell environment, every other kept variable comes from it, and one only the inherited environment has is dropped, except that Unix PATH appends inherited directories after the login shell directories. Without a resolved environment (resolved is nil), kept variables come from inherited.
Types ¶
type Agent ¶
type Agent struct {
// Resolve returns the login shell's SSH_AUTH_SOCK.
Resolve func(ctx context.Context) (string, error)
// Retry spaces login shell runs after a failure; zero is
// DefaultAgentRetry.
Retry time.Duration
// Now is a seam for tests.
Now func() time.Time
// contains filtered or unexported fields
}
Agent keeps a long-lived process's SSH agent socket usable. The socket in its environment goes stale when the session that provided it ends (an ssh login closes, an agent restarts); a stale socket is replaced by the login shell's, or dropped, so a fetch fails clearly instead of using it.
The shell is asked only when a socket this process had has gone stale: a user without an agent never pays for a shell run. An answer without a usable socket is remembered; a failed run is retried after Retry. Callers share one run and never wait on each other otherwise.
type Options ¶
type Options struct {
// Shell is the login shell; empty uses $SHELL from Environ, then the
// user database.
Shell string
// Printer is the program, and its leading arguments, that prints the
// environment with PrintEnv; Resolve appends the marker. Empty runs this
// executable as "daemon print-env".
Printer []string
// Timeout bounds the shell; zero means DefaultTimeout.
Timeout time.Duration
// Environ is the inherited environment the session variables are taken
// from; nil uses os.Environ().
Environ []string
}
Options configure Resolve.
type Result ¶
type Result struct {
Shell string
Env map[string]string
// Fallback is why the interactive login shell printed no environment,
// when a login shell that is not interactive printed Env instead.
Fallback string
}
Result is a resolved environment and the shell that produced it.
func Resolve ¶
Resolve runs the login shell and returns the environment it set up. When the interactive shell prints no environment, a login shell that is not interactive is asked within the same timeout (see Result.Fallback). A shell that is slow, or prints no environment either way, is an error; callers fall back to the inherited environment.